<?php

use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\CoreExtension;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;
use Twig\TemplateWrapper;

/* @UVDeskCoreFramework/mxClient.js */
class __TwigTemplate_109d6524660497517daa353a71f25324 extends Template
{
    private Source $source;
    /**
     * @var array<string, Template>
     */
    private array $macros = [];

    public function __construct(Environment $env)
    {
        parent::__construct($env);

        $this->source = $this->getSourceContext();

        $this->parent = false;

        $this->blocks = [
        ];
    }

    protected function doDisplay(array $context, array $blocks = []): iterable
    {
        $macros = $this->macros;
        // line 1
        yield "/**
 * Copyright (c) 2006-2017, JGraph Ltd
 * Copyright (c) 2006-2017, Gaudenz Alder
 */
var mxClient =
{
\t/**
\t * Class: mxClient
\t *
\t * Bootstrapping mechanism for the mxGraph thin client. The production version
\t * of this file contains all code required to run the mxGraph thin client, as
\t * well as global constants to identify the browser and operating system in
\t * use. You may have to load chrome://global/content/contentAreaUtils.js in
\t * your page to disable certain security restrictions in Mozilla.
\t * 
\t * Variable: VERSION
\t *
\t * Contains the current version of the mxGraph library. The strings that
\t * communicate versions of mxGraph use the following format.
\t * 
\t * versionMajor.versionMinor.buildNumber.revisionNumber
\t * 
\t * Current version is 4.2.2.
\t */
\tVERSION: '4.2.2',

\t/**
\t * Variable: IS_IE
\t *
\t * True if the current browser is Internet Explorer 10 or below. Use <mxClient.IS_IE11>
\t * to detect IE 11.
\t */
\tIS_IE: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE') >= 0,

\t/**
\t * Variable: IS_IE6
\t *
\t * True if the current browser is Internet Explorer 6.x.
\t */
\tIS_IE6: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE 6') >= 0,

\t/**
\t * Variable: IS_IE11
\t *
\t * True if the current browser is Internet Explorer 11.x.
\t */
\tIS_IE11: navigator.userAgent != null && !!navigator.userAgent.match(/Trident\\/7\\./),

\t/**
\t * Variable: IS_EDGE
\t *
\t * True if the current browser is Microsoft Edge.
\t */
\tIS_EDGE: navigator.userAgent != null && !!navigator.userAgent.match(/Edge\\//),

\t/**
\t * Variable: IS_QUIRKS
\t *
\t * True if the current browser is Internet Explorer and it is in quirks mode.
\t */
\tIS_QUIRKS: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE') >= 0 &&
\t\t(document.documentMode == null || document.documentMode == 5),

\t/**
\t * Variable: IS_EM
\t * 
\t * True if the browser is IE11 in enterprise mode (IE8 standards mode).
\t */
\tIS_EM: 'spellcheck' in document.createElement('textarea') && document.documentMode == 8,

\t/**
\t * Variable: VML_PREFIX
\t * 
\t * Prefix for VML namespace in node names. Default is 'v'.
\t */
\tVML_PREFIX: 'v',

\t/**
\t * Variable: OFFICE_PREFIX
\t * 
\t * Prefix for VML office namespace in node names. Default is 'o'.
\t */
\tOFFICE_PREFIX: 'o',

\t/**
\t * Variable: IS_NS
\t *
\t * True if the current browser is Netscape (including Firefox).
\t */
  \tIS_NS: navigator.userAgent != null &&
  \t\tnavigator.userAgent.indexOf('Mozilla/') >= 0 &&
  \t\tnavigator.userAgent.indexOf('MSIE') < 0 &&
  \t\tnavigator.userAgent.indexOf('Edge/') < 0,

\t/**
\t * Variable: IS_OP
\t *
\t * True if the current browser is Opera.
\t */
  \tIS_OP: navigator.userAgent != null &&
  \t\t(navigator.userAgent.indexOf('Opera/') >= 0 ||
  \t\tnavigator.userAgent.indexOf('OPR/') >= 0),

\t/**
\t * Variable: IS_OT
\t *
\t * True if -o-transform is available as a CSS style, ie for Opera browsers
\t * based on a Presto engine with version 2.5 or later.
\t */
  \tIS_OT: navigator.userAgent != null &&
  \t\tnavigator.userAgent.indexOf('Presto/') >= 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/2.4.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/2.3.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/2.2.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/2.1.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/2.0.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Presto/1.') < 0,
  \t
\t/**
\t * Variable: IS_SF
\t *
\t * True if the current browser is Safari.
\t */
  \tIS_SF: /Apple Computer, Inc/.test(navigator.vendor),

\t/**
\t * Variable: IS_ANDROID
\t * 
\t * Returns true if the user agent contains Android.
\t */
  \tIS_ANDROID: navigator.appVersion.indexOf('Android') >= 0,

\t/**
\t * Variable: IS_IOS
\t * 
\t * Returns true if the user agent is an iPad, iPhone or iPod.
\t */
  \tIS_IOS: (/iP(hone|od|ad)/.test(navigator.platform)),

\t/**
\t * Variable: IS_GC
\t *
\t * True if the current browser is Google Chrome.
\t */
  \tIS_GC: /Google Inc/.test(navigator.vendor),
\t
\t/**
\t * Variable: IS_CHROMEAPP
\t *
\t * True if the this is running inside a Chrome App.
\t */
  \tIS_CHROMEAPP: window.chrome != null && chrome.app != null && chrome.app.runtime != null,

\t/**
\t * Variable: IS_FF
\t *
\t * True if the current browser is Firefox.
\t */
  \tIS_FF: typeof InstallTrigger !== 'undefined',
  \t
\t/**
\t * Variable: IS_MT
\t *
\t * True if -moz-transform is available as a CSS style. This is the case
\t * for all Firefox-based browsers newer than or equal 3, such as Camino,
\t * Iceweasel, Seamonkey and Iceape.
\t */
  \tIS_MT: (navigator.userAgent.indexOf('Firefox/') >= 0 &&
\t\tnavigator.userAgent.indexOf('Firefox/1.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Firefox/2.') < 0) ||
  \t\t(navigator.userAgent.indexOf('Iceweasel/') >= 0 &&
  \t\tnavigator.userAgent.indexOf('Iceweasel/1.') < 0 &&
  \t\tnavigator.userAgent.indexOf('Iceweasel/2.') < 0) ||
  \t\t(navigator.userAgent.indexOf('SeaMonkey/') >= 0 &&
  \t\tnavigator.userAgent.indexOf('SeaMonkey/1.') < 0) ||
  \t\t(navigator.userAgent.indexOf('Iceape/') >= 0 &&
  \t\tnavigator.userAgent.indexOf('Iceape/1.') < 0),

\t/**
\t * Variable: IS_VML
\t *
\t * True if the browser supports VML.
\t */
  \tIS_VML: navigator.appName.toUpperCase() == 'MICROSOFT INTERNET EXPLORER',

\t/**
\t * Variable: IS_SVG
\t *
\t * True if the browser supports SVG.
\t */
  \tIS_SVG: navigator.appName.toUpperCase() != 'MICROSOFT INTERNET EXPLORER',

\t/**
\t * Variable: NO_FO
\t *
\t * True if foreignObject support is not available. This is the case for
\t * Opera, older SVG-based browsers and all versions of IE.
\t */
  \tNO_FO: !document.createElementNS || document.createElementNS('http://www.w3.org/2000/svg',
  \t\t'foreignObject') != '[object SVGForeignObjectElement]' || navigator.userAgent.indexOf('Opera/') >= 0,

\t/**
\t * Variable: IS_WIN
\t *
\t * True if the client is a Windows.
\t */
  \tIS_WIN: navigator.appVersion.indexOf('Win') > 0,

\t/**
\t * Variable: IS_MAC
\t *
\t * True if the client is a Mac.
\t */
  \tIS_MAC: navigator.appVersion.indexOf('Mac') > 0,
\t
\t/**
\t * Variable: IS_CHROMEOS
\t *
\t * True if the client is a Chrome OS.
\t */
  \tIS_CHROMEOS: /\\bCrOS\\b/.test(navigator.appVersion),

\t/**
\t * Variable: IS_TOUCH
\t * 
\t * True if this device supports touchstart/-move/-end events (Apple iOS,
\t * Android, Chromebook and Chrome Browser on touch-enabled devices).
\t */
  \tIS_TOUCH: 'ontouchstart' in document.documentElement,

\t/**
\t * Variable: IS_POINTER
\t * 
\t * True if this device supports Microsoft pointer events (always false on Macs).
\t */
  \tIS_POINTER: window.PointerEvent != null && !(navigator.appVersion.indexOf('Mac') > 0),

\t/**
\t * Variable: IS_LOCAL
\t *
\t * True if the documents location does not start with http:// or https://.
\t */
  \tIS_LOCAL: document.location.href.indexOf('http://') < 0 &&
  \t\t\t  document.location.href.indexOf('https://') < 0,

\t/**
\t * Variable: defaultBundles
\t * 
\t * Contains the base names of the default bundles if mxLoadResources is false.
\t */
  \tdefaultBundles: [],

\t/**
\t * Function: isBrowserSupported
\t *
\t * Returns true if the current browser is supported, that is, if
\t * <mxClient.IS_VML> or <mxClient.IS_SVG> is true.
\t * 
\t * Example:
\t * 
\t * (code)
\t * if (!mxClient.isBrowserSupported())
\t * {
\t *   mxUtils.error('Browser is not supported!', 200, false);
\t * }
\t * (end)
\t */
\tisBrowserSupported: function()
\t{
\t\treturn mxClient.IS_VML || mxClient.IS_SVG;
\t},

\t/**
\t * Function: link
\t *
\t * Adds a link node to the head of the document. Use this
\t * to add a stylesheet to the page as follows:
\t *
\t * (code)
\t * mxClient.link('stylesheet', filename);
\t * (end)
\t *
\t * where filename is the (relative) URL of the stylesheet. The charset
\t * is hardcoded to ISO-8859-1 and the type is text/css.
\t * 
\t * Parameters:
\t * 
\t * rel - String that represents the rel attribute of the link node.
\t * href - String that represents the href attribute of the link node.
\t * doc - Optional parent document of the link node.
\t * id - unique id for the link element to check if it already exists
\t */
\tlink: function(rel, href, doc, id)
\t{
\t\tdoc = doc || document;

\t\t// Workaround for Operation Aborted in IE6 if base tag is used in head
\t\tif (mxClient.IS_IE6)
\t\t{
\t\t\tdoc.write('<link rel=\"' + rel + '\" href=\"' + href + '\" charset=\"UTF-8\" type=\"text/css\"/>');
\t\t}
\t\telse
\t\t{\t
\t\t\tvar link = doc.createElement('link');
\t\t\t
\t\t\tlink.setAttribute('rel', rel);
\t\t\tlink.setAttribute('href', href);
\t\t\tlink.setAttribute('charset', 'UTF-8');
\t\t\tlink.setAttribute('type', 'text/css');
\t\t\t
\t\t\tif (id)
\t\t\t{
\t\t\t\tlink.setAttribute('id', id);
\t\t\t}
\t\t\t
\t\t\tvar head = doc.getElementsByTagName('head')[0];
\t   \t\thead.appendChild(link);
\t\t}
\t},
\t
\t/**
\t * Function: loadResources
\t * 
\t * Helper method to load the default bundles if mxLoadResources is false.
\t * 
\t * Parameters:
\t * 
\t * fn - Function to call after all resources have been loaded.
\t * lan - Optional string to pass to <mxResources.add>.
\t */
\tloadResources: function(fn, lan)
\t{
\t\tvar pending = mxClient.defaultBundles.length;
\t\t
\t\tfunction callback()
\t\t{
\t\t\tif (--pending == 0)
\t\t\t{
\t\t\t\tfn();
\t\t\t}
\t\t}
\t\t
\t\tfor (var i = 0; i < mxClient.defaultBundles.length; i++)
\t\t{
\t\t\tmxResources.add(mxClient.defaultBundles[i], lan, callback);
\t\t}
\t},
\t
\t/**
\t * Function: include
\t *
\t * Dynamically adds a script node to the document header.
\t * 
\t * In production environments, the includes are resolved in the mxClient.js
\t * file to reduce the number of requests required for client startup. This
\t * function should only be used in development environments, but not in
\t * production systems.
\t */
\tinclude: function(src)
\t{
\t\tdocument.write('<script src=\"'+src+'\"></script>');
\t}
};

/**
 * Variable: mxLoadResources
 * 
 * Optional global config variable to toggle loading of the two resource files
 * in <mxGraph> and <mxEditor>. Default is true. NOTE: This is a global variable,
 * not a variable of mxClient. If this is false, you can use <mxClient.loadResources>
 * with its callback to load the default bundles asynchronously.
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tvar mxLoadResources = false;
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 */
if (typeof(mxLoadResources) == 'undefined')
{
\tmxLoadResources = true;
}

/**
 * Variable: mxForceIncludes
 * 
 * Optional global config variable to force loading the JavaScript files in
 * development mode. Default is undefined. NOTE: This is a global variable,
 * not a variable of mxClient.
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tvar mxLoadResources = true;
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 */
if (typeof(mxForceIncludes) == 'undefined')
{
\tmxForceIncludes = false;
}

/**
 * Variable: mxResourceExtension
 * 
 * Optional global config variable to specify the extension of resource files.
 * Default is true. NOTE: This is a global variable, not a variable of mxClient.
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tvar mxResourceExtension = '.txt';
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 */
if (typeof(mxResourceExtension) == 'undefined')
{
\tmxResourceExtension = '.txt';
}

/**
 * Variable: mxLoadStylesheets
 * 
 * Optional global config variable to toggle loading of the CSS files when
 * the library is initialized. Default is true. NOTE: This is a global variable,
 * not a variable of mxClient.
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tvar mxLoadStylesheets = false;
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 */
if (typeof(mxLoadStylesheets) == 'undefined')
{
\tmxLoadStylesheets = true;
}

/**
 * Variable: basePath
 *
 * Basepath for all URLs in the core without trailing slash. Default is '.'.
 * Set mxBasePath prior to loading the mxClient library as follows to override
 * this setting:
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tmxBasePath = '/path/to/core/directory';
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 * 
 * When using a relative path, the path is relative to the URL of the page that
 * contains the assignment. Trailing slashes are automatically removed.
 */
if (typeof(mxBasePath) != 'undefined' && mxBasePath.length > 0)
{
\t// Adds a trailing slash if required
\tif (mxBasePath.substring(mxBasePath.length - 1) == '/')
\t{
\t\tmxBasePath = mxBasePath.substring(0, mxBasePath.length - 1);
\t}

\tmxClient.basePath = mxBasePath;
}
else
{
\tmxClient.basePath = '.';
}

/**
 * Variable: imageBasePath
 *
 * Basepath for all images URLs in the core without trailing slash. Default is
 * <mxClient.basePath> + '/images'. Set mxImageBasePath prior to loading the
 * mxClient library as follows to override this setting:
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tmxImageBasePath = '/path/to/image/directory';
 * </script>
 * <script type=\"text/javascript\" src=\"/path/to/core/directory/js/mxClient.js\"></script>
 * (end)
 * 
 * When using a relative path, the path is relative to the URL of the page that
 * contains the assignment. Trailing slashes are automatically removed.
 */
if (typeof(mxImageBasePath) != 'undefined' && mxImageBasePath.length > 0)
{
\t// Adds a trailing slash if required
\tif (mxImageBasePath.substring(mxImageBasePath.length - 1) == '/')
\t{
\t\tmxImageBasePath = mxImageBasePath.substring(0, mxImageBasePath.length - 1);
\t}

\tmxClient.imageBasePath = mxImageBasePath;
}
else
{
\tmxClient.imageBasePath = mxClient.basePath + '/images';\t
}

/**
 * Variable: language
 *
 * Defines the language of the client, eg. en for english, de for german etc.
 * The special value 'none' will disable all built-in internationalization and
 * resource loading. See <mxResources.getSpecialBundle> for handling identifiers
 * with and without a dash.
 * 
 * Set mxLanguage prior to loading the mxClient library as follows to override
 * this setting:
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tmxLanguage = 'en';
 * </script>
 * <script type=\"text/javascript\" src=\"js/mxClient.js\"></script>
 * (end)
 * 
 * If internationalization is disabled, then the following variables should be
 * overridden to reflect the current language of the system. These variables are
 * cleared when i18n is disabled.
 * <mxEditor.askZoomResource>, <mxEditor.lastSavedResource>,
 * <mxEditor.currentFileResource>, <mxEditor.propertiesResource>,
 * <mxEditor.tasksResource>, <mxEditor.helpResource>, <mxEditor.outlineResource>,
 * <mxElbowEdgeHandler.doubleClickOrientationResource>, <mxUtils.errorResource>,
 * <mxUtils.closeResource>, <mxGraphSelectionModel.doneResource>,
 * <mxGraphSelectionModel.updatingSelectionResource>, <mxGraphView.doneResource>,
 * <mxGraphView.updatingDocumentResource>, <mxCellRenderer.collapseExpandResource>,
 * <mxGraph.containsValidationErrorsResource> and
 * <mxGraph.alreadyConnectedResource>.
 */
if (typeof(mxLanguage) != 'undefined' && mxLanguage != null)
{
\tmxClient.language = mxLanguage;
}
else
{
\tmxClient.language = (mxClient.IS_IE) ? navigator.userLanguage : navigator.language;
}

/**
 * Variable: defaultLanguage
 * 
 * Defines the default language which is used in the common resource files. Any
 * resources for this language will only load the common resource file, but not
 * the language-specific resource file. Default is 'en'.
 * 
 * Set mxDefaultLanguage prior to loading the mxClient library as follows to override
 * this setting:
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tmxDefaultLanguage = 'de';
 * </script>
 * <script type=\"text/javascript\" src=\"js/mxClient.js\"></script>
 * (end)
 */
if (typeof(mxDefaultLanguage) != 'undefined' && mxDefaultLanguage != null)
{
\tmxClient.defaultLanguage = mxDefaultLanguage;
}
else
{
\tmxClient.defaultLanguage = 'en';
}

// Adds all required stylesheets and namespaces
if (mxLoadStylesheets)
{
\tmxClient.link('stylesheet', mxClient.basePath + '/css/common.css');
}

/**
 * Variable: languages
 *
 * Defines the optional array of all supported language extensions. The default
 * language does not have to be part of this list. See
 * <mxResources.isLanguageSupported>.
 *
 * (code)
 * <script type=\"text/javascript\">
 * \t\tmxLanguages = ['de', 'it', 'fr'];
 * </script>
 * <script type=\"text/javascript\" src=\"js/mxClient.js\"></script>
 * (end)
 * 
 * This is used to avoid unnecessary requests to language files, ie. if a 404
 * will be returned.
 */
if (typeof(mxLanguages) != 'undefined' && mxLanguages != null)
{
\tmxClient.languages = mxLanguages;
}

// Adds required namespaces, stylesheets and memory handling for older IE browsers
if (mxClient.IS_VML)
{
\tif (mxClient.IS_SVG)
\t{
\t\tmxClient.IS_VML = false;
\t}
\telse
\t{
\t\t// Enables support for IE8 standards mode. Note that this requires all attributes for VML
\t\t// elements to be set using direct notation, ie. node.attr = value, not setAttribute.
\t\tif (document.namespaces != null)
\t\t{
\t\t\tif (document.documentMode == 8)
\t\t\t{
\t\t\t\tdocument.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml', '#default#VML');
\t\t\t\tdocument.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office', '#default#VML');
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdocument.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml');
\t\t\t\tdocument.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office');
\t\t\t}
\t\t}

\t\t// Workaround for limited number of stylesheets in IE (does not work in standards mode)
\t\tif (mxClient.IS_QUIRKS && document.styleSheets.length >= 30)
\t\t{
\t\t\t(function()
\t\t\t{
\t\t\t\tvar node = document.createElement('style');
\t\t\t\tnode.type = 'text/css';
\t\t\t\tnode.styleSheet.cssText = mxClient.VML_PREFIX + '\\\\:*{behavior:url(#default#VML)}' +
\t\t        \tmxClient.OFFICE_PREFIX + '\\\\:*{behavior:url(#default#VML)}';
\t\t        document.getElementsByTagName('head')[0].appendChild(node);
\t\t\t})();
\t\t}
\t\telse
\t\t{
\t\t\tdocument.createStyleSheet().cssText = mxClient.VML_PREFIX + '\\\\:*{behavior:url(#default#VML)}' +
\t\t    \tmxClient.OFFICE_PREFIX + '\\\\:*{behavior:url(#default#VML)}';
\t\t}
\t    
\t    if (mxLoadStylesheets)
\t    {
\t    \tmxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css');
\t    }
\t}
}

/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxLog =
{
\t/**
\t * Class: mxLog
\t * 
\t * A singleton class that implements a simple console.
\t * 
\t * Variable: consoleName
\t * 
\t * Specifies the name of the console window. Default is 'Console'.
\t */
\tconsoleName: 'Console',
\t
\t/**
\t * Variable: TRACE
\t * 
\t * Specified if the output for <enter> and <leave> should be visible in the
\t * console. Default is false.
\t */
\tTRACE: false,

\t/**
\t * Variable: DEBUG
\t * 
\t * Specifies if the output for <debug> should be visible in the console.
\t * Default is true.
\t */
\tDEBUG: true,

\t/**
\t * Variable: WARN
\t * 
\t * Specifies if the output for <warn> should be visible in the console.
\t * Default is true.
\t */
\tWARN: true,

\t/**
\t * Variable: buffer
\t * 
\t * Buffer for pre-initialized content.
\t */
\tbuffer: '',
\t
\t/**
\t * Function: init
\t *
\t * Initializes the DOM node for the console. This requires document.body to
\t * point to a non-null value. This is called from within <setVisible> if the
\t * log has not yet been initialized.
\t */
\tinit: function()
\t{
\t\tif (mxLog.window == null && document.body != null)
\t\t{
\t\t\tvar title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION;

\t\t\t// Creates a table that maintains the layout
\t\t\tvar table = document.createElement('table');
\t\t\ttable.setAttribute('width', '100%');
\t\t\ttable.setAttribute('height', '100%');

\t\t\tvar tbody = document.createElement('tbody');
\t\t\tvar tr = document.createElement('tr');
\t\t\tvar td = document.createElement('td');
\t\t\ttd.style.verticalAlign = 'top';
\t\t\t\t
\t\t\t// Adds the actual console as a textarea
\t\t\tmxLog.textarea = document.createElement('textarea');
\t\t\tmxLog.textarea.setAttribute('wrap', 'off');
\t\t\tmxLog.textarea.setAttribute('readOnly', 'true');
\t\t\tmxLog.textarea.style.height = '100%';
\t\t\tmxLog.textarea.style.resize = 'none';
\t\t\tmxLog.textarea.value = mxLog.buffer;

\t\t\t// Workaround for wrong width in standards mode
\t\t\tif (mxClient.IS_NS && document.compatMode != 'BackCompat')
\t\t\t{
\t\t\t\tmxLog.textarea.style.width = '99%';
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tmxLog.textarea.style.width = '100%';
\t\t\t}
\t\t\t
\t\t\ttd.appendChild(mxLog.textarea);
\t\t\ttr.appendChild(td);
\t\t\ttbody.appendChild(tr);

\t\t\t// Creates the container div
\t\t\ttr = document.createElement('tr');
\t\t\tmxLog.td = document.createElement('td');
\t\t\tmxLog.td.style.verticalAlign = 'top';
\t\t\tmxLog.td.setAttribute('height', '30px');
\t\t\t
\t\t\ttr.appendChild(mxLog.td);
\t\t\ttbody.appendChild(tr);
\t\t\ttable.appendChild(tbody);

\t\t\t// Adds various debugging buttons
\t\t\tmxLog.addButton('Info', function (evt)
\t\t\t{
\t\t\t\tmxLog.info();
\t\t\t});
\t\t
\t\t\tmxLog.addButton('DOM', function (evt)
\t\t\t{
\t\t\t\tvar content = mxUtils.getInnerHtml(document.body);
\t\t\t\tmxLog.debug(content);
\t\t\t});
\t
\t\t\tmxLog.addButton('Trace', function (evt)
\t\t\t{
\t\t\t\tmxLog.TRACE = !mxLog.TRACE;
\t\t\t\t
\t\t\t\tif (mxLog.TRACE)
\t\t\t\t{
\t\t\t\t\tmxLog.debug('Tracing enabled');
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tmxLog.debug('Tracing disabled');
\t\t\t\t}
\t\t\t});\t

\t\t\tmxLog.addButton('Copy', function (evt)
\t\t\t{
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\tmxUtils.copy(mxLog.textarea.value);
\t\t\t\t}
\t\t\t\tcatch (err)
\t\t\t\t{
\t\t\t\t\tmxUtils.alert(err);
\t\t\t\t}
\t\t\t});\t\t\t

\t\t\tmxLog.addButton('Show', function (evt)
\t\t\t{
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\tmxUtils.popup(mxLog.textarea.value);
\t\t\t\t}
\t\t\t\tcatch (err)
\t\t\t\t{
\t\t\t\t\tmxUtils.alert(err);
\t\t\t\t}
\t\t\t});\t
\t\t\t
\t\t\tmxLog.addButton('Clear', function (evt)
\t\t\t{
\t\t\t\tmxLog.textarea.value = '';
\t\t\t});

\t\t\t// Cross-browser code to get window size
\t\t\tvar h = 0;
\t\t\tvar w = 0;
\t\t\t
\t\t\tif (typeof(window.innerWidth) === 'number')
\t\t\t{
\t\t\t\th = window.innerHeight;
\t\t\t\tw = window.innerWidth;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\th = (document.documentElement.clientHeight || document.body.clientHeight);
\t\t\t\tw = document.body.clientWidth;
\t\t\t}

\t\t\tmxLog.window = new mxWindow(title, table, Math.max(0, w - 320), Math.max(0, h - 210), 300, 160);
\t\t\tmxLog.window.setMaximizable(true);
\t\t\tmxLog.window.setScrollable(false);
\t\t\tmxLog.window.setResizable(true);
\t\t\tmxLog.window.setClosable(true);
\t\t\tmxLog.window.destroyOnClose = false;
\t\t\t
\t\t\t// Workaround for ignored textarea height in various setups
\t\t\tif (((mxClient.IS_NS || mxClient.IS_IE) && !mxClient.IS_GC &&
\t\t\t\t!mxClient.IS_SF && document.compatMode != 'BackCompat') ||
\t\t\t\tdocument.documentMode == 11)
\t\t\t{
\t\t\t\tvar elt = mxLog.window.getElement();
\t\t\t\t
\t\t\t\tvar resizeHandler = function(sender, evt)
\t\t\t\t{
\t\t\t\t\tmxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70) + 'px';
\t\t\t\t}; 
\t\t\t\t
\t\t\t\tmxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler);
\t\t\t\tmxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler);
\t\t\t\tmxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler);

\t\t\t\tmxLog.textarea.style.height = '92px';
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: info
\t * 
\t * Writes the current navigator information to the console.
\t */
\tinfo: function()
\t{
\t\tmxLog.writeln(mxUtils.toString(navigator));
\t},
\t\t\t
\t/**
\t * Function: addButton
\t * 
\t * Adds a button to the console using the given label and function.
\t */
\taddButton: function(lab, funct)
\t{
\t\tvar button = document.createElement('button');
\t\tmxUtils.write(button, lab);
\t\tmxEvent.addListener(button, 'click', funct);
\t\tmxLog.td.appendChild(button);
\t},
\t\t\t\t
\t/**
\t * Function: isVisible
\t * 
\t * Returns true if the console is visible.
\t */
\tisVisible: function()
\t{
\t\tif (mxLog.window != null)
\t\t{
\t\t\treturn mxLog.window.isVisible();
\t\t}
\t\t
\t\treturn false;
\t},
\t

\t/**
\t * Function: show
\t * 
\t * Shows the console.
\t */
\tshow: function()
\t{
\t\tmxLog.setVisible(true);
\t},

\t/**
\t * Function: setVisible
\t * 
\t * Shows or hides the console.
\t */
\tsetVisible: function(visible)
\t{
\t\tif (mxLog.window == null)
\t\t{
\t\t\tmxLog.init();
\t\t}

\t\tif (mxLog.window != null)
\t\t{
\t\t\tmxLog.window.setVisible(visible);
\t\t}
\t},

\t/**
\t * Function: enter
\t * 
\t * Writes the specified string to the console
\t * if <TRACE> is true and returns the current 
\t * time in milliseconds.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxLog.show();
\t * var t0 = mxLog.enter('Hello');
\t * // Do something
\t * mxLog.leave('World!', t0);
\t * (end)
\t */
\tenter: function(string)
\t{
\t\tif (mxLog.TRACE)
\t\t{
\t\t\tmxLog.writeln('Entering '+string);
\t\t\t
\t\t\treturn new Date().getTime();
\t\t}
\t},

\t/**
\t * Function: leave
\t * 
\t * Writes the specified string to the console
\t * if <TRACE> is true and computes the difference
\t * between the current time and t0 in milliseconds.
\t * See <enter> for an example.
\t */
\tleave: function(string, t0)
\t{
\t\tif (mxLog.TRACE)
\t\t{
\t\t\tvar dt = (t0 != 0) ? ' ('+(new Date().getTime() - t0)+' ms)' : '';
\t\t\tmxLog.writeln('Leaving '+string+dt);
\t\t}
\t},
\t
\t/**
\t * Function: debug
\t * 
\t * Adds all arguments to the console if <DEBUG> is enabled.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxLog.show();
\t * mxLog.debug('Hello, World!');
\t * (end)
\t */
\tdebug: function()
\t{
\t\tif (mxLog.DEBUG)
\t\t{
\t\t\tmxLog.writeln.apply(this, arguments);
\t\t}
\t},
\t
\t/**
\t * Function: warn
\t * 
\t * Adds all arguments to the console if <WARN> is enabled.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxLog.show();
\t * mxLog.warn('Hello, World!');
\t * (end)
\t */
\twarn: function()
\t{
\t\tif (mxLog.WARN)
\t\t{
\t\t\tmxLog.writeln.apply(this, arguments);
\t\t}
\t},

\t/**
\t * Function: write
\t * 
\t * Adds the specified strings to the console.
\t */
\twrite: function()
\t{
\t\tvar string = '';
\t\t
\t\tfor (var i = 0; i < arguments.length; i++)
\t\t{
\t\t\tstring += arguments[i];
\t\t\t
\t\t\tif (i < arguments.length - 1)
\t\t\t{
\t\t\t\tstring += ' ';
\t\t\t}
\t\t}
\t\t
\t\tif (mxLog.textarea != null)
\t\t{
\t\t\tmxLog.textarea.value = mxLog.textarea.value + string;

\t\t\t// Workaround for no update in Presto 2.5.22 (Opera 10.5)
\t\t\tif (navigator.userAgent != null &&
\t\t\t\tnavigator.userAgent.indexOf('Presto/2.5') >= 0)
\t\t\t{
\t\t\t\tmxLog.textarea.style.visibility = 'hidden';
\t\t\t\tmxLog.textarea.style.visibility = 'visible';
\t\t\t}
\t\t\t
\t\t\tmxLog.textarea.scrollTop = mxLog.textarea.scrollHeight;
\t\t}
\t\telse
\t\t{
\t\t\tmxLog.buffer += string;
\t\t}
\t},
\t
\t/**
\t * Function: writeln
\t * 
\t * Adds the specified strings to the console, appending a linefeed at the
\t * end of each string.
\t */
\twriteln: function()
\t{
\t\tvar string = '';
\t\t
\t\tfor (var i = 0; i < arguments.length; i++)
\t\t{
\t\t\tstring += arguments[i];
\t\t\t
\t\t\tif (i < arguments.length - 1)
\t\t\t{
\t\t\t\tstring += ' ';
\t\t\t}
\t\t}

\t\tmxLog.write(string + '\\n');
\t}
\t
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxObjectIdentity =
{
\t/**
\t * Class: mxObjectIdentity
\t * 
\t * Identity for JavaScript objects and functions. This is implemented using
\t * a simple incrementing counter which is stored in each object under
\t * <FIELD_NAME>.
\t * 
\t * The identity for an object does not change during its lifecycle.
\t * 
\t * Variable: FIELD_NAME
\t * 
\t * Name of the field to be used to store the object ID. Default is
\t * <code>mxObjectId</code>.
\t */
\tFIELD_NAME: 'mxObjectId',

\t/**
\t * Variable: counter
\t * 
\t * Current counter.
\t */
\tcounter: 0,

\t/**
\t * Function: get
\t * 
\t * Returns the ID for the given object or function or null if no object
\t * is specified.
\t */
\tget: function(obj)
\t{
\t\tif (obj != null)
\t\t{
\t\t\tif (obj[mxObjectIdentity.FIELD_NAME] == null)
\t\t\t{
\t\t\t\tif (typeof obj === 'object')
\t\t\t\t{
\t\t\t\t\tvar ctor = mxUtils.getFunctionName(obj.constructor);
\t\t\t\t\tobj[mxObjectIdentity.FIELD_NAME] = ctor + '#' + mxObjectIdentity.counter++;
\t\t\t\t}
\t\t\t\telse if (typeof obj === 'function')
\t\t\t\t{
\t\t\t\t\tobj[mxObjectIdentity.FIELD_NAME] = 'Function#' + mxObjectIdentity.counter++;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\treturn obj[mxObjectIdentity.FIELD_NAME];
\t\t}
\t\t
\t\treturn null;
\t},

\t/**
\t * Function: clear
\t * 
\t * Deletes the ID from the given object or function.
\t */
\tclear: function(obj)
\t{
\t\tif (typeof(obj) === 'object' || typeof obj === 'function')
\t\t{
\t\t\tdelete obj[mxObjectIdentity.FIELD_NAME];
\t\t}
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDictionary
 *
 * A wrapper class for an associative array with object keys. Note: This
 * implementation uses <mxObjectIdentitiy> to turn object keys into strings.
 * 
 * Constructor: mxEventSource
 *
 * Constructs a new dictionary which allows object to be used as keys.
 */
function mxDictionary()
{
\tthis.clear();
};

/**
 * Function: map
 *
 * Stores the (key, value) pairs in this dictionary.
 */
mxDictionary.prototype.map = null;

/**
 * Function: clear
 *
 * Clears the dictionary.
 */
mxDictionary.prototype.clear = function()
{
\tthis.map = {};
};

/**
 * Function: get
 *
 * Returns the value for the given key.
 */
mxDictionary.prototype.get = function(key)
{
\tvar id = mxObjectIdentity.get(key);
\t
\treturn this.map[id];
};

/**
 * Function: put
 *
 * Stores the value under the given key and returns the previous
 * value for that key.
 */
mxDictionary.prototype.put = function(key, value)
{
\tvar id = mxObjectIdentity.get(key);
\tvar previous = this.map[id];
\tthis.map[id] = value;
\t
\treturn previous;
};

/**
 * Function: remove
 *
 * Removes the value for the given key and returns the value that
 * has been removed.
 */
mxDictionary.prototype.remove = function(key)
{
\tvar id = mxObjectIdentity.get(key);
\tvar previous = this.map[id];
\tdelete this.map[id];
\t
\treturn previous;
};

/**
 * Function: getKeys
 *
 * Returns all keys as an array.
 */
mxDictionary.prototype.getKeys = function()
{
\tvar result = [];
\t
\tfor (var key in this.map)
\t{
\t\tresult.push(key);
\t}
\t
\treturn result;
};

/**
 * Function: getValues
 *
 * Returns all values as an array.
 */
mxDictionary.prototype.getValues = function()
{
\tvar result = [];
\t
\tfor (var key in this.map)
\t{
\t\tresult.push(this.map[key]);
\t}
\t
\treturn result;
};

/**
 * Function: visit
 *
 * Visits all entries in the dictionary using the given function with the
 * following signature: function(key, value) where key is a string and
 * value is an object.
 * 
 * Parameters:
 * 
 * visitor - A function that takes the key and value as arguments.
 */
mxDictionary.prototype.visit = function(visitor)
{
\tfor (var key in this.map)
\t{
\t\tvisitor(key, this.map[key]);
\t}
};
/**
 * Copyright (c) 2006-2016, JGraph Ltd
 * Copyright (c) 2006-2016, Gaudenz Alder
 */
var mxResources =
{
\t/**
\t * Class: mxResources
\t * 
\t * Implements internationalization. You can provide any number of 
\t * resource files on the server using the following format for the 
\t * filename: name[-en].properties. The en stands for any lowercase 
\t * 2-character language shortcut (eg. de for german, fr for french).
\t *
\t * If the optional language extension is omitted, then the file is used as a 
\t * default resource which is loaded in all cases. If a properties file for a 
\t * specific language exists, then it is used to override the settings in the 
\t * default resource. All entries in the file are of the form key=value. The
\t * values may then be accessed in code via <get>. Lines without 
\t * equal signs in the properties files are ignored.
\t *
\t * Resource files may either be added programmatically using
\t * <add> or via a resource tag in the UI section of the 
\t * editor configuration file, eg:
\t * 
\t * (code)
\t * <mxEditor>
\t *   <ui>
\t *     <resource basename=\"examples/resources/mxWorkflow\"/>
\t * (end)
\t * 
\t * The above element will load examples/resources/mxWorkflow.properties as well
\t * as the language specific file for the current language, if it exists.
\t * 
\t * Values may contain placeholders of the form {1}...{n} where each placeholder
\t * is replaced with the value of the corresponding array element in the params
\t * argument passed to <mxResources.get>. The placeholder {1} maps to the first
\t * element in the array (at index 0).
\t * 
\t * See <mxClient.language> for more information on specifying the default
\t * language or disabling all loading of resources.
\t * 
\t * Lines that start with a # sign will be ignored.
\t * 
\t * Special characters
\t * 
\t * To use unicode characters, use the standard notation (eg. \\u8fd1) or %u as a
\t * prefix (eg. %u20AC will display a Euro sign). For normal hex encoded strings,
\t * use % as a prefix, eg. %F6 will display a \"o umlaut\" (&ouml;).
\t * 
\t * See <resourcesEncoded> to disable this. If you disable this, make sure that
\t * your files are UTF-8 encoded.
\t * 
\t * Asynchronous loading
\t * 
\t * By default, the core adds two resource files synchronously at load time.
\t * To load these files asynchronously, set <mxLoadResources> to false
\t * before loading mxClient.js and use <mxResources.loadResources> instead.
\t * 
\t * Variable: resources
\t * 
\t * Object that maps from keys to values.
\t */
\tresources: {},

\t/**
\t * Variable: extension
\t * 
\t * Specifies the extension used for language files. Default is <mxResourceExtension>.
\t */
\textension: mxResourceExtension,

\t/**
\t * Variable: resourcesEncoded
\t * 
\t * Specifies whether or not values in resource files are encoded with \\u or
\t * percentage. Default is false.
\t */
\tresourcesEncoded: false,

\t/**
\t * Variable: loadDefaultBundle
\t * 
\t * Specifies if the default file for a given basename should be loaded.
\t * Default is true.
\t */
\tloadDefaultBundle: true,

\t/**
\t * Variable: loadDefaultBundle
\t * 
\t * Specifies if the specific language file file for a given basename should
\t * be loaded. Default is true.
\t */
\tloadSpecialBundle: true,

\t/**
\t * Function: isLanguageSupported
\t * 
\t * Hook for subclassers to disable support for a given language. This
\t * implementation returns true if lan is in <mxClient.languages>.
\t * 
\t * Parameters:
\t *
\t * lan - The current language.
\t */
\tisLanguageSupported: function(lan)
\t{
\t\tif (mxClient.languages != null)
\t\t{
\t\t\treturn mxUtils.indexOf(mxClient.languages, lan) >= 0;
\t\t}
\t\t
\t\treturn true;
\t},

\t/**
\t * Function: getDefaultBundle
\t * 
\t * Hook for subclassers to return the URL for the special bundle. This
\t * implementation returns basename + <extension> or null if
\t * <loadDefaultBundle> is false.
\t * 
\t * Parameters:
\t * 
\t * basename - The basename for which the file should be loaded.
\t * lan - The current language.
\t */
\tgetDefaultBundle: function(basename, lan)
\t{
\t\tif (mxResources.loadDefaultBundle || !mxResources.isLanguageSupported(lan))
\t\t{
\t\t\treturn basename + mxResources.extension;
\t\t}
\t\telse
\t\t{
\t\t\treturn null;
\t\t}
\t},

\t/**
\t * Function: getSpecialBundle
\t * 
\t * Hook for subclassers to return the URL for the special bundle. This
\t * implementation returns basename + '_' + lan + <extension> or null if
\t * <loadSpecialBundle> is false or lan equals <mxClient.defaultLanguage>.
\t * 
\t * If <mxResources.languages> is not null and <mxClient.language> contains
\t * a dash, then this method checks if <isLanguageSupported> returns true
\t * for the full language (including the dash). If that returns false the
\t * first part of the language (up to the dash) will be tried as an extension.
\t * 
\t * If <mxResources.language> is null then the first part of the language is
\t * used to maintain backwards compatibility.
\t * 
\t * Parameters:
\t * 
\t * basename - The basename for which the file should be loaded.
\t * lan - The language for which the file should be loaded.
\t */
\tgetSpecialBundle: function(basename, lan)
\t{
\t\tif (mxClient.languages == null || !this.isLanguageSupported(lan))
\t\t{
\t\t\tvar dash = lan.indexOf('-');
\t\t\t
\t\t\tif (dash > 0)
\t\t\t{
\t\t\t\tlan = lan.substring(0, dash);
\t\t\t}
\t\t}

\t\tif (mxResources.loadSpecialBundle && mxResources.isLanguageSupported(lan) && lan != mxClient.defaultLanguage)
\t\t{
\t\t\treturn basename + '_' + lan + mxResources.extension;
\t\t}
\t\telse
\t\t{
\t\t\treturn null;
\t\t}
\t},

\t/**
\t * Function: add
\t * 
\t * Adds the default and current language properties file for the specified
\t * basename. Existing keys are overridden as new files are added. If no
\t * callback is used then the request is synchronous.
\t *
\t * Example:
\t * 
\t * At application startup, additional resources may be 
\t * added using the following code:
\t * 
\t * (code)
\t * mxResources.add('resources/editor');
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * basename - The basename for which the file should be loaded.
\t * lan - The language for which the file should be loaded.
\t * callback - Optional callback for asynchronous loading.
\t */
\tadd: function(basename, lan, callback)
\t{
\t\tlan = (lan != null) ? lan : ((mxClient.language != null) ?
\t\t\tmxClient.language.toLowerCase() : mxConstants.NONE);
\t\t
\t\tif (lan != mxConstants.NONE)
\t\t{
\t\t\tvar defaultBundle = mxResources.getDefaultBundle(basename, lan);
\t\t\tvar specialBundle = mxResources.getSpecialBundle(basename, lan);
\t\t\t
\t\t\tvar loadSpecialBundle = function()
\t\t\t{
\t\t\t\tif (specialBundle != null)
\t\t\t\t{
\t\t\t\t\tif (callback)
\t\t\t\t\t{
\t\t\t\t\t\tmxUtils.get(specialBundle, function(req)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tmxResources.parse(req.getText());
\t\t\t\t\t\t\tcallback();
\t\t\t\t\t\t}, function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcallback();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\ttry
\t\t\t\t\t\t{
\t\t\t\t\t   \t\tvar req = mxUtils.load(specialBundle);
\t\t\t\t\t   \t\t
\t\t\t\t\t   \t\tif (req.isReady())
\t\t\t\t\t   \t\t{
\t\t\t\t\t \t   \t\tmxResources.parse(req.getText());
\t\t\t\t\t   \t\t}
\t\t\t\t   \t\t}
\t\t\t\t   \t\tcatch (e)
\t\t\t\t   \t\t{
\t\t\t\t   \t\t\t// ignore
\t\t\t\t\t   \t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (callback != null)
\t\t\t\t{
\t\t\t\t\tcallback();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (defaultBundle != null)
\t\t\t{
\t\t\t\tif (callback)
\t\t\t\t{
\t\t\t\t\tmxUtils.get(defaultBundle, function(req)
\t\t\t\t\t{
\t\t\t\t\t\tmxResources.parse(req.getText());
\t\t\t\t\t\tloadSpecialBundle();
\t\t\t\t\t}, function()
\t\t\t\t\t{
\t\t\t\t\t\tloadSpecialBundle();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttry
\t\t\t\t\t{
\t\t\t\t   \t\tvar req = mxUtils.load(defaultBundle);
\t\t\t\t   \t\t
\t\t\t\t   \t\tif (req.isReady())
\t\t\t\t   \t\t{
\t\t\t\t \t   \t\tmxResources.parse(req.getText());
\t\t\t\t   \t\t}
\t\t\t\t   \t\t
\t\t\t\t   \t\tloadSpecialBundle();
\t\t\t\t  \t}
\t\t\t\t  \tcatch (e)
\t\t\t\t  \t{
\t\t\t\t  \t\t// ignore
\t\t\t\t  \t}
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Overlays the language specific file (_lan-extension)
\t\t\t\tloadSpecialBundle();
\t\t\t}
\t\t}
\t},

\t/**
\t * Function: parse
\t * 
\t * Parses the key, value pairs in the specified
\t * text and stores them as local resources.
\t */
\tparse: function(text)
\t{
\t\tif (text != null)
\t\t{
\t\t\tvar lines = text.split('\\n');
\t\t\t
\t\t\tfor (var i = 0; i < lines.length; i++)
\t\t\t{
\t\t\t\tif (lines[i].charAt(0) != '#')
\t\t\t\t{
\t\t\t\t\tvar index = lines[i].indexOf('=');
\t\t\t\t\t
\t\t\t\t\tif (index > 0)
\t\t\t\t\t{
\t\t\t\t\t\tvar key = lines[i].substring(0, index);
\t\t\t\t\t\tvar idx = lines[i].length;
\t\t\t\t\t\t
\t\t\t\t\t\tif (lines[i].charCodeAt(idx - 1) == 13)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tidx--;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tvar value = lines[i].substring(index + 1, idx);
\t\t\t\t\t\t
\t\t\t\t\t\tif (this.resourcesEncoded)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvalue = value.replace(/\\\\(?=u[a-fA-F\\d]{4})/g,\"%\");
\t\t\t\t\t\t\tmxResources.resources[key] = unescape(value);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tmxResources.resources[key] = value;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t},

\t/**
\t * Function: get
\t * 
\t * Returns the value for the specified resource key.
\t *
\t * Example:
\t * To read the value for 'welomeMessage', use the following:
\t * (code)
\t * var result = mxResources.get('welcomeMessage') || '';
\t * (end)
\t *
\t * This would require an entry of the following form in
\t * one of the English language resource files:
\t * (code)
\t * welcomeMessage=Welcome to mxGraph!
\t * (end)
\t * 
\t * The part behind the || is the string value to be used if the given
\t * resource is not available.
\t * 
\t * Parameters:
\t * 
\t * key - String that represents the key of the resource to be returned.
\t * params - Array of the values for the placeholders of the form {1}...{n}
\t * to be replaced with in the resulting string.
\t * defaultValue - Optional string that specifies the default return value.
\t */
\tget: function(key, params, defaultValue)
\t{
\t\tvar value = mxResources.resources[key];
\t\t
\t\t// Applies the default value if no resource was found
\t\tif (value == null)
\t\t{
\t\t\tvalue = defaultValue;
\t\t}
\t\t
\t\t// Replaces the placeholders with the values in the array
\t\tif (value != null && params != null)
\t\t{
\t\t\tvalue = mxResources.replacePlaceholders(value, params);
\t\t}
\t\t
\t\treturn value;
\t},

\t/**
\t * Function: replacePlaceholders
\t * 
\t * Replaces the given placeholders with the given parameters.
\t * 
\t * Parameters:
\t * 
\t * value - String that contains the placeholders.
\t * params - Array of the values for the placeholders of the form {1}...{n}
\t * to be replaced with in the resulting string.
\t */
\treplacePlaceholders: function(value, params)
\t{
\t\tvar result = [];
\t\tvar index = null;
\t\t
\t\tfor (var i = 0; i < value.length; i++)
\t\t{
\t\t\tvar c = value.charAt(i);

\t\t\tif (c == '{')
\t\t\t{
\t\t\t\tindex = '';
\t\t\t}
\t\t\telse if (index != null && \tc == '}')
\t\t\t{
\t\t\t\tindex = parseInt(index)-1;
\t\t\t\t
\t\t\t\tif (index >= 0 && index < params.length)
\t\t\t\t{
\t\t\t\t\tresult.push(params[index]);
\t\t\t\t}
\t\t\t\t
\t\t\t\tindex = null;
\t\t\t}
\t\t\telse if (index != null)
\t\t\t{
\t\t\t\tindex += c;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.push(c);
\t\t\t}
\t\t}
\t\t
\t\treturn result.join('');
\t},

\t/**
\t * Function: loadResources
\t * 
\t * Loads all required resources asynchronously. Use this to load the graph and
\t * editor resources if <mxLoadResources> is false.
\t * 
\t * Parameters:
\t * 
\t * callback - Callback function for asynchronous loading.
\t */
\tloadResources: function(callback)
\t{
\t\tmxResources.add(mxClient.basePath+'/resources/editor', null, function()
\t\t{
\t\t\tmxResources.add(mxClient.basePath+'/resources/graph', null, callback);
\t\t});
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPoint
 *
 * Implements a 2-dimensional vector with double precision coordinates.
 * 
 * Constructor: mxPoint
 *
 * Constructs a new point for the optional x and y coordinates. If no
 * coordinates are given, then the default values for <x> and <y> are used.
 */
function mxPoint(x, y)
{
\tthis.x = (x != null) ? x : 0;
\tthis.y = (y != null) ? y : 0;
};

/**
 * Variable: x
 *
 * Holds the x-coordinate of the point. Default is 0.
 */
mxPoint.prototype.x = null;

/**
 * Variable: y
 *
 * Holds the y-coordinate of the point. Default is 0.
 */
mxPoint.prototype.y = null;

/**
 * Function: equals
 * 
 * Returns true if the given object equals this point.
 */
mxPoint.prototype.equals = function(obj)
{
\treturn obj != null && obj.x == this.x && obj.y == this.y;
};

/**
 * Function: clone
 *
 * Returns a clone of this <mxPoint>.
 */
mxPoint.prototype.clone = function()
{
\t// Handles subclasses as well
\treturn mxUtils.clone(this);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxRectangle
 *
 * Extends <mxPoint> to implement a 2-dimensional rectangle with double
 * precision coordinates.
 * 
 * Constructor: mxRectangle
 *
 * Constructs a new rectangle for the optional parameters. If no parameters
 * are given then the respective default values are used.
 */
function mxRectangle(x, y, width, height)
{
\tmxPoint.call(this, x, y);

\tthis.width = (width != null) ? width : 0;
\tthis.height = (height != null) ? height : 0;
};

/**
 * Extends mxPoint.
 */
mxRectangle.prototype = new mxPoint();
mxRectangle.prototype.constructor = mxRectangle;

/**
 * Variable: width
 *
 * Holds the width of the rectangle. Default is 0.
 */
mxRectangle.prototype.width = null;

/**
 * Variable: height
 *
 * Holds the height of the rectangle. Default is 0.
 */
mxRectangle.prototype.height = null;

/**
 * Function: setRect
 * 
 * Sets this rectangle to the specified values
 */
mxRectangle.prototype.setRect = function(x, y, w, h)
{
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;
};

/**
 * Function: getCenterX
 * 
 * Returns the x-coordinate of the center point.
 */
mxRectangle.prototype.getCenterX = function ()
{
\treturn this.x + this.width/2;
};

/**
 * Function: getCenterY
 * 
 * Returns the y-coordinate of the center point.
 */
mxRectangle.prototype.getCenterY = function ()
{
\treturn this.y + this.height/2;
};

/**
 * Function: add
 *
 * Adds the given rectangle to this rectangle.
 */
mxRectangle.prototype.add = function(rect)
{
\tif (rect != null)
\t{
\t\tvar minX = Math.min(this.x, rect.x);
\t\tvar minY = Math.min(this.y, rect.y);
\t\tvar maxX = Math.max(this.x + this.width, rect.x + rect.width);
\t\tvar maxY = Math.max(this.y + this.height, rect.y + rect.height);
\t\t
\t\tthis.x = minX;
\t\tthis.y = minY;
\t\tthis.width = maxX - minX;
\t\tthis.height = maxY - minY;
\t}
};

/**
 * Function: intersect
 * 
 * Changes this rectangle to where it overlaps with the given rectangle.
 */
mxRectangle.prototype.intersect = function(rect)
{
\tif (rect != null)
\t{
\t\tvar r1 = this.x + this.width;
\t\tvar r2 = rect.x + rect.width;
\t\t
\t\tvar b1 = this.y + this.height;
\t\tvar b2 = rect.y + rect.height;
\t\t
\t\tthis.x = Math.max(this.x, rect.x);
\t\tthis.y = Math.max(this.y, rect.y);
\t\tthis.width = Math.min(r1, r2) - this.x;
\t\tthis.height = Math.min(b1, b2) - this.y;
\t}
};

/**
 * Function: grow
 *
 * Grows the rectangle by the given amount, that is, this method subtracts
 * the given amount from the x- and y-coordinates and adds twice the amount
 * to the width and height.
 */
mxRectangle.prototype.grow = function(amount)
{
\tthis.x -= amount;
\tthis.y -= amount;
\tthis.width += 2 * amount;
\tthis.height += 2 * amount;
\t
\treturn this;
};

/**
 * Function: getPoint
 * 
 * Returns the top, left corner as a new <mxPoint>.
 */
mxRectangle.prototype.getPoint = function()
{
\treturn new mxPoint(this.x, this.y);
};

/**
 * Function: rotate90
 * 
 * Rotates this rectangle by 90 degree around its center point.
 */
mxRectangle.prototype.rotate90 = function()
{
\tvar t = (this.width - this.height) / 2;
\tthis.x += t;
\tthis.y -= t;
\tvar tmp = this.width;
\tthis.width = this.height;
\tthis.height = tmp;
};

/**
 * Function: equals
 * 
 * Returns true if the given object equals this rectangle.
 */
mxRectangle.prototype.equals = function(obj)
{
\treturn obj != null && obj.x == this.x && obj.y == this.y &&
\t\tobj.width == this.width && obj.height == this.height;
};

/**
 * Function: fromRectangle
 * 
 * Returns a new <mxRectangle> which is a copy of the given rectangle.
 */
mxRectangle.fromRectangle = function(rect)
{
\treturn new mxRectangle(rect.x, rect.y, rect.width, rect.height);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxEffects =
{

\t/**
\t * Class: mxEffects
\t * 
\t * Provides animation effects.
\t */

\t/**
\t * Function: animateChanges
\t * 
\t * Asynchronous animated move operation. See also: <mxMorphing>.
\t * 
\t * Example:
\t * 
\t * (code)
\t * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
\t * {
\t *   var changes = evt.getProperty('edit').changes;
\t * 
\t *   if (changes.length < 10)
\t *   {
\t *     mxEffects.animateChanges(graph, changes);
\t *   }
\t * });
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> that received the changes.
\t * changes - Array of changes to be animated.
\t * done - Optional function argument that is invoked after the
\t * last step of the animation.
\t */
\tanimateChanges: function(graph, changes, done)
\t{
\t\tvar maxStep = 10;
\t\tvar step = 0;

\t\tvar animate = function() 
\t\t{
\t\t\tvar isRequired = false;
\t\t\t
\t\t\tfor (var i = 0; i < changes.length; i++)
\t\t\t{
\t\t\t\tvar change = changes[i];
\t\t\t\t
\t\t\t\tif (change instanceof mxGeometryChange ||
\t\t\t\t\tchange instanceof mxTerminalChange ||
\t\t\t\t\tchange instanceof mxValueChange ||
\t\t\t\t\tchange instanceof mxChildChange ||
\t\t\t\t\tchange instanceof mxStyleChange)
\t\t\t\t{
\t\t\t\t\tvar state = graph.getView().getState(change.cell || change.child, false);
\t\t\t\t\t
\t\t\t\t\tif (state != null)
\t\t\t\t\t{
\t\t\t\t\t\tisRequired = true;
\t\t\t\t\t
\t\t\t\t\t\tif (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tmxUtils.setOpacity(state.shape.node, 100 * step / maxStep);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar scale = graph.getView().scale;\t\t\t\t\t

\t\t\t\t\t\t\tvar dx = (change.geometry.x - change.previous.x) * scale;
\t\t\t\t\t\t\tvar dy = (change.geometry.y - change.previous.y) * scale;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar sx = (change.geometry.width - change.previous.width) * scale;
\t\t\t\t\t\t\tvar sy = (change.geometry.height - change.previous.height) * scale;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (step == 0)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.x -= dx;
\t\t\t\t\t\t\t\tstate.y -= dy;
\t\t\t\t\t\t\t\tstate.width -= sx;
\t\t\t\t\t\t\t\tstate.height -= sy;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.x += dx / maxStep;
\t\t\t\t\t\t\t\tstate.y += dy / maxStep;
\t\t\t\t\t\t\t\tstate.width += sx / maxStep;
\t\t\t\t\t\t\t\tstate.height += sy / maxStep;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tgraph.cellRenderer.redraw(state);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Fades all connected edges and children
\t\t\t\t\t\t\tmxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tif (step < maxStep && isRequired)
\t\t\t{
\t\t\t\tstep++;
\t\t\t\twindow.setTimeout(animate, delay);
\t\t\t}
\t\t\telse if (done != null)
\t\t\t{
\t\t\t\tdone();
\t\t\t}
\t\t};
\t\t
\t\tvar delay = 30;
\t\tanimate();
\t},
    
\t/**
\t * Function: cascadeOpacity
\t * 
\t * Sets the opacity on the given cell and its descendants.
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> that contains the cells.
\t * cell - <mxCell> to set the opacity for.
\t * opacity - New value for the opacity in %.
\t */
    cascadeOpacity: function(graph, cell, opacity)
\t{
\t\t// Fades all children
\t\tvar childCount = graph.model.getChildCount(cell);
\t\t
\t\tfor (var i=0; i<childCount; i++)
\t\t{
\t\t\tvar child = graph.model.getChildAt(cell, i);
\t\t\tvar childState = graph.getView().getState(child);
\t\t\t
\t\t\tif (childState != null)
\t\t\t{
\t\t\t\tmxUtils.setOpacity(childState.shape.node, opacity);
\t\t\t\tmxEffects.cascadeOpacity(graph, child, opacity);
\t\t\t}
\t\t}
\t\t
\t\t// Fades all connected edges
\t\tvar edges = graph.model.getEdges(cell);
\t\t
\t\tif (edges != null)
\t\t{
\t\t\tfor (var i=0; i<edges.length; i++)
\t\t\t{
\t\t\t\tvar edgeState = graph.getView().getState(edges[i]);
\t\t\t\t
\t\t\t\tif (edgeState != null)
\t\t\t\t{
\t\t\t\t\tmxUtils.setOpacity(edgeState.shape.node, opacity);
\t\t\t\t}
\t\t\t}
\t\t}
\t},

\t/**
\t * Function: fadeOut
\t * 
\t * Asynchronous fade-out operation.
\t */
\tfadeOut: function(node, from, remove, step, delay, isEnabled)
\t{
\t\tstep = step || 40;
\t\tdelay = delay || 30;
\t\t
\t\tvar opacity = from || 100;
\t\t
\t\tmxUtils.setOpacity(node, opacity);
\t\t
\t\tif (isEnabled || isEnabled == null)
\t\t{
\t\t\tvar f = function()
\t\t\t{
\t\t\t    opacity = Math.max(opacity-step, 0);
\t\t\t\tmxUtils.setOpacity(node, opacity);
\t\t\t\t
\t\t\t\tif (opacity > 0)
\t\t\t\t{
\t\t\t\t\twindow.setTimeout(f, delay);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tnode.style.visibility = 'hidden';
\t\t\t\t\t
\t\t\t\t\tif (remove && node.parentNode)
\t\t\t\t\t{
\t\t\t\t\t\tnode.parentNode.removeChild(node);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t};
\t\t\twindow.setTimeout(f, delay);
\t\t}
\t\telse
\t\t{
\t\t\tnode.style.visibility = 'hidden';
\t\t\t
\t\t\tif (remove && node.parentNode)
\t\t\t{
\t\t\t\tnode.parentNode.removeChild(node);
\t\t\t}
\t\t}
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxUtils =
{
\t/**
\t * Class: mxUtils
\t * 
\t * A singleton class that provides cross-browser helper methods.
\t * This is a global functionality. To access the functions in this
\t * class, use the global classname appended by the functionname.
\t * You may have to load chrome://global/content/contentAreaUtils.js
\t * to disable certain security restrictions in Mozilla for the <open>,
\t * <save>, <saveAs> and <copy> function.
\t * 
\t * For example, the following code displays an error message:
\t * 
\t * (code)
\t * mxUtils.error('Browser is not supported!', 200, false);
\t * (end)
\t * 
\t * Variable: errorResource
\t * 
\t * Specifies the resource key for the title of the error window. If the
\t * resource for this key does not exist then the value is used as
\t * the title. Default is 'error'.
\t */
\terrorResource: (mxClient.language != 'none') ? 'error' : '',
\t
\t/**
\t * Variable: closeResource
\t * 
\t * Specifies the resource key for the label of the close button. If the
\t * resource for this key does not exist then the value is used as
\t * the label. Default is 'close'.
\t */
\tcloseResource: (mxClient.language != 'none') ? 'close' : '',

\t/**
\t * Variable: errorImage
\t * 
\t * Defines the image used for error dialogs.
\t */
\terrorImage: mxClient.imageBasePath + '/error.gif',
\t
\t/**
\t * Function: removeCursors
\t * 
\t * Removes the cursors from the style of the given DOM node and its
\t * descendants.
\t * 
\t * Parameters:
\t * 
\t * element - DOM node to remove the cursor style from.
\t */
\tremoveCursors: function(element)
\t{
\t\tif (element.style != null)
\t\t{
\t\t\telement.style.cursor = '';
\t\t}
\t\t
\t\tvar children = element.childNodes;
\t\t
\t\tif (children != null)
\t\t{
\t        var childCount = children.length;
\t        
\t        for (var i = 0; i < childCount; i += 1)
\t        {
\t            mxUtils.removeCursors(children[i]);
\t        }
\t    }
\t},

\t/**
\t * Function: getCurrentStyle
\t * 
\t * Returns the current style of the specified element.
\t * 
\t * Parameters:
\t * 
\t * element - DOM node whose current style should be returned.
\t */
\tgetCurrentStyle: function()
\t{
\t\tif (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 9))
\t\t{
\t\t\treturn function(element)
\t\t\t{
\t\t\t\treturn (element != null) ? element.currentStyle : null;
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function(element)
\t\t\t{
\t\t\t\treturn (element != null) ?
\t\t\t\t\twindow.getComputedStyle(element, '') :
\t\t\t\t\tnull;
\t\t\t};
\t\t}
\t}(),
\t
\t/**
\t * Function: parseCssNumber
\t * 
\t * Parses the given CSS numeric value adding handling for the values thin,
\t * medium and thick (2, 4 and 6).
\t */
\tparseCssNumber: function(value)
\t{
\t\tif (value == 'thin')
\t\t{
\t\t\tvalue = '2';
\t\t}
\t\telse if (value == 'medium')
\t\t{
\t\t\tvalue = '4';
\t\t}
\t\telse if (value == 'thick')
\t\t{
\t\t\tvalue = '6';
\t\t}
\t\t
\t\tvalue = parseFloat(value);
\t\t
\t\tif (isNaN(value))
\t\t{
\t\t\tvalue = 0;
\t\t}
\t\t
\t\treturn value;
\t},

\t/**
\t * Function: setPrefixedStyle
\t * 
\t * Adds the given style with the standard name and an optional vendor prefix for the current
\t * browser.
\t * 
\t * (code)
\t * mxUtils.setPrefixedStyle(node.style, 'transformOrigin', '0% 0%');
\t * (end)
\t */
\tsetPrefixedStyle: function()
\t{
\t\tvar prefix = null;
\t\t
\t\tif (mxClient.IS_OT)
\t\t{
\t\t\tprefix = 'O';
\t\t}
\t\telse if (mxClient.IS_SF || mxClient.IS_GC)
\t\t{
\t\t\tprefix = 'Webkit';
\t\t}
\t\telse if (mxClient.IS_MT)
\t\t{
\t\t\tprefix = 'Moz';
\t\t}
\t\telse if (mxClient.IS_IE && document.documentMode >= 9 && document.documentMode < 10)
\t\t{
\t\t\tprefix = 'ms';
\t\t}

\t\treturn function(style, name, value)
\t\t{
\t\t\tstyle[name] = value;
\t\t\t
\t\t\tif (prefix != null && name.length > 0)
\t\t\t{
\t\t\t\tname = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
\t\t\t\tstyle[name] = value;
\t\t\t}
\t\t};
\t}(),
\t
\t/**
\t * Function: hasScrollbars
\t * 
\t * Returns true if the overflow CSS property of the given node is either
\t * scroll or auto.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node whose style should be checked for scrollbars.
\t */
\thasScrollbars: function(node)
\t{
\t\tvar style = mxUtils.getCurrentStyle(node);

\t\treturn style != null && (style.overflow == 'scroll' || style.overflow == 'auto');
\t},
\t
\t/**
\t * Function: bind
\t * 
\t * Returns a wrapper function that locks the execution scope of the given
\t * function to the specified scope. Inside funct, the \"this\" keyword
\t * becomes a reference to that scope.
\t */
\tbind: function(scope, funct)
\t{
\t\treturn function()
\t\t{
\t\t\treturn funct.apply(scope, arguments);
\t\t};
\t},
\t
\t/**
\t * Function: eval
\t * 
\t * Evaluates the given expression using eval and returns the JavaScript
\t * object that represents the expression result. Supports evaluation of
\t * expressions that define functions and returns the function object for
\t * these expressions.
\t * 
\t * Parameters:
\t * 
\t * expr - A string that represents a JavaScript expression.
\t */
\teval: function(expr)
\t{
\t\tvar result = null;

\t\tif (expr.indexOf('function') >= 0)
\t\t{
\t\t\ttry
\t\t\t{
\t\t\t\teval('var _mxJavaScriptExpression='+expr);
\t\t\t\tresult = _mxJavaScriptExpression;
\t\t\t\t// TODO: Use delete here?
\t\t\t\t_mxJavaScriptExpression = null;
\t\t\t}
\t\t\tcatch (e)
\t\t\t{
\t\t\t\tmxLog.warn(e.message + ' while evaluating ' + expr);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\ttry
\t\t\t{
\t\t\t\tresult = eval(expr);
\t\t\t}
\t\t\tcatch (e)
\t\t\t{
\t\t\t\tmxLog.warn(e.message + ' while evaluating ' + expr);
\t\t\t}
\t\t}
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: findNode
\t * 
\t * Returns the first node where attr equals value.
\t * This implementation does not use XPath.
\t */
\tfindNode: function(node, attr, value)
\t{
\t\tif (node.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t{
\t\t\tvar tmp = node.getAttribute(attr);
\t
\t\t\tif (tmp != null && tmp == value)
\t\t\t{
\t\t\t\treturn node;
\t\t\t}
\t\t}
\t\t
\t\tnode = node.firstChild;
\t\t
\t\twhile (node != null)
\t\t{
\t\t\tvar result = mxUtils.findNode(node, attr, value);
\t\t\t
\t\t\tif (result != null)
\t\t\t{
\t\t\t\treturn result;
\t\t\t}
\t\t\t
\t\t\tnode = node.nextSibling;
\t\t}
\t\t
\t\treturn null;
\t},

\t/**
\t * Function: getFunctionName
\t * 
\t * Returns the name for the given function.
\t * 
\t * Parameters:
\t * 
\t * f - JavaScript object that represents a function.
\t */
\tgetFunctionName: function(f)
\t{
\t\tvar str = null;

\t\tif (f != null)
\t\t{
\t\t\tif (f.name != null)
\t\t\t{
\t\t\t\tstr = f.name;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tstr = mxUtils.trim(f.toString());
\t\t\t\t
\t\t\t\tif (/^function\\s/.test(str))
\t\t\t\t{
\t\t\t\t\tstr = mxUtils.ltrim(str.substring(9));
\t\t\t\t\tvar idx2 = str.indexOf('(');
\t\t\t\t\t
\t\t\t\t\tif (idx2 > 0)
\t\t\t\t\t{
\t\t\t\t\t\tstr = str.substring(0, idx2);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn str;
\t},

\t/**
\t * Function: indexOf
\t * 
\t * Returns the index of obj in array or -1 if the array does not contain
\t * the given object.
\t * 
\t * Parameters:
\t * 
\t * array - Array to check for the given obj.
\t * obj - Object to find in the given array.
\t */
\tindexOf: function(array, obj)
\t{
\t\tif (array != null && obj != null)
\t\t{
\t\t\tfor (var i = 0; i < array.length; i++)
\t\t\t{
\t\t\t\tif (array[i] == obj)
\t\t\t\t{
\t\t\t\t\treturn i;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn -1;
\t},

\t/**
\t * Function: forEach
\t * 
\t * Calls the given function for each element of the given array and returns
\t * the array.
\t * 
\t * Parameters:
\t * 
\t * array - Array that contains the elements.
\t * fn - Function to be called for each object.
\t */
\tforEach: function(array, fn)
\t{
\t\tif (array != null && fn != null)
\t\t{
\t\t\tfor (var i = 0; i < array.length; i++)
\t\t\t{
\t\t\t\tfn(array[i]);
\t\t\t}
\t\t}
\t\t
\t\treturn array;
\t},

\t/**
\t * Function: remove
\t * 
\t * Removes all occurrences of the given object in the given array or
\t * object. If there are multiple occurrences of the object, be they
\t * associative or as an array entry, all occurrences are removed from
\t * the array or deleted from the object. By removing the object from
\t * the array, all elements following the removed element are shifted
\t * by one step towards the beginning of the array.
\t * 
\t * The length of arrays is not modified inside this function.
\t * 
\t * Parameters:
\t * 
\t * obj - Object to find in the given array.
\t * array - Array to check for the given obj.
\t */
\tremove: function(obj, array)
\t{
\t\tvar result = null;
\t\t
\t\tif (typeof(array) == 'object')
\t\t{
\t\t\tvar index = mxUtils.indexOf(array, obj);
\t\t\t
\t\t\twhile (index >= 0)
\t\t\t{
\t\t\t\tarray.splice(index, 1);
\t\t\t\tresult = obj;
\t\t\t\tindex = mxUtils.indexOf(array, obj);
\t\t\t}
\t\t}

\t\tfor (var key in array)
\t\t{
\t\t\tif (array[key] == obj)
\t\t\t{
\t\t\t\tdelete array[key];
\t\t\t\tresult = obj;
\t\t\t}
\t\t}
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: isNode
\t * 
\t * Returns true if the given value is an XML node with the node name
\t * and if the optional attribute has the specified value.
\t * 
\t * This implementation assumes that the given value is a DOM node if the
\t * nodeType property is numeric, that is, if isNaN returns false for
\t * value.nodeType.
\t * 
\t * Parameters:
\t * 
\t * value - Object that should be examined as a node.
\t * nodeName - String that specifies the node name.
\t * attributeName - Optional attribute name to check.
\t * attributeValue - Optional attribute value to check.
\t */
\t isNode: function(value, nodeName, attributeName, attributeValue)
\t {
\t \tif (value != null && !isNaN(value.nodeType) && (nodeName == null ||
\t \t\tvalue.nodeName.toLowerCase() == nodeName.toLowerCase()))
 \t\t{
 \t\t\treturn attributeName == null ||
 \t\t\t\tvalue.getAttribute(attributeName) == attributeValue;
 \t\t}
\t \t
\t \treturn false;
\t },
\t
\t/**
\t * Function: isAncestorNode
\t * 
\t * Returns true if the given ancestor is an ancestor of the
\t * given DOM node in the DOM. This also returns true if the
\t * child is the ancestor.
\t * 
\t * Parameters:
\t * 
\t * ancestor - DOM node that represents the ancestor.
\t * child - DOM node that represents the child.
\t */
\t isAncestorNode: function(ancestor, child)
\t {
\t \tvar parent = child;
\t \t
\t \twhile (parent != null)
\t \t{
\t \t\tif (parent == ancestor)
\t \t\t{
\t \t\t\treturn true;
\t \t\t}

\t \t\tparent = parent.parentNode;
\t \t}
\t \t
\t \treturn false;
\t },

\t/**
\t * Function: getChildNodes
\t * 
\t * Returns an array of child nodes that are of the given node type.
\t * 
\t * Parameters:
\t * 
\t * node - Parent DOM node to return the children from.
\t * nodeType - Optional node type to return. Default is
\t * <mxConstants.NODETYPE_ELEMENT>.
\t */
\tgetChildNodes: function(node, nodeType)
\t{
\t\tnodeType = nodeType || mxConstants.NODETYPE_ELEMENT;
\t\t
\t\tvar children = [];
\t\tvar tmp = node.firstChild;
\t\t
\t\twhile (tmp != null)
\t\t{
\t\t\tif (tmp.nodeType == nodeType)
\t\t\t{
\t\t\t\tchildren.push(tmp);
\t\t\t}
\t\t\t
\t\t\ttmp = tmp.nextSibling;
\t\t}
\t\t
\t\treturn children;
\t},

\t/**
\t * Function: importNode
\t * 
\t * Cross browser implementation for document.importNode. Uses document.importNode
\t * in all browsers but IE, where the node is cloned by creating a new node and
\t * copying all attributes and children into it using importNode, recursively.
\t * 
\t * Parameters:
\t * 
\t * doc - Document to import the node into.
\t * node - Node to be imported.
\t * allChildren - If all children should be imported.
\t */
\timportNode: function(doc, node, allChildren)
\t{
\t\tif (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 10))
\t\t{
\t\t\treturn mxUtils.importNodeImplementation(doc, node, allChildren);
\t\t}
\t\telse
\t\t{
\t\t\treturn doc.importNode(node, allChildren);
\t\t}
\t},

\t/**
\t * Function: importNodeImplementation
\t * 
\t * Full DOM API implementation for importNode without using importNode API call.
\t * 
\t * Parameters:
\t * 
\t * doc - Document to import the node into.
\t * node - Node to be imported.
\t * allChildren - If all children should be imported.
\t */
\timportNodeImplementation: function(doc, node, allChildren)
\t{
\t\tswitch (node.nodeType)
\t\t{
\t\t\tcase 1: /* element */
\t\t\t{
\t\t\t\tvar newNode = doc.createElement(node.nodeName);
\t\t\t\t
\t\t\t\tif (node.attributes && node.attributes.length > 0)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < node.attributes.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tnewNode.setAttribute(node.attributes[i].nodeName,
\t\t\t\t\t\t\tnode.getAttribute(node.attributes[i].nodeName));
\t\t\t\t\t}\t
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (allChildren && node.childNodes && node.childNodes.length > 0)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < node.childNodes.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tnewNode.appendChild(mxUtils.importNodeImplementation(doc, node.childNodes[i], allChildren));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn newNode;
\t\t\t\tbreak;
\t\t\t}
\t\t\tcase 3: /* text */
\t\t    case 4: /* cdata-section */
\t\t    case 8: /* comment */
\t\t    {
\t\t    \treturn doc.createTextNode((node.nodeValue != null) ? node.nodeValue : node.value);
\t\t    \tbreak;
\t\t    }
\t\t};
\t},

\t/**
\t * Function: createXmlDocument
\t * 
\t * Returns a new, empty XML document.
\t */
\tcreateXmlDocument: function()
\t{
\t\tvar doc = null;
\t\t
\t\tif (document.implementation && document.implementation.createDocument)
\t\t{
\t\t\tdoc = document.implementation.createDocument('', '', null);
\t\t}
\t\telse if (\"ActiveXObject\" in window)
\t\t{
\t\t\tdoc = mxUtils.createMsXmlDocument();
\t \t}
\t \t
\t \treturn doc;
\t},

\t/**
\t * Function: createMsXmlDocument
\t * 
\t * Returns a new, empty Microsoft.XMLDOM document using ActiveXObject.
\t */
\tcreateMsXmlDocument: function()
\t{
\t\tvar doc = new ActiveXObject('Microsoft.XMLDOM');
\t\tdoc.async = false;

\t\t// Workaround for parsing errors with SVG DTD
\t\tdoc.validateOnParse = false;
\t\tdoc.resolveExternals = false;
\t \t
\t \treturn doc;
\t},

\t/**
\t * Function: parseXml
\t * 
\t * Parses the specified XML string into a new XML document and returns the
\t * new document.
\t * 
\t * Example:
\t * 
\t * (code)
\t * var doc = mxUtils.parseXml(
\t *   '<mxGraphModel><root><MyDiagram id=\"0\"><mxCell/></MyDiagram>'+
\t *   '<MyLayer id=\"1\"><mxCell parent=\"0\" /></MyLayer><MyObject id=\"2\">'+
\t *   '<mxCell style=\"strokeColor=blue;fillColor=red\" parent=\"1\" vertex=\"1\">'+
\t *   '<mxGeometry x=\"10\" y=\"10\" width=\"80\" height=\"30\" as=\"geometry\"/>'+
\t *   '</mxCell></MyObject></root></mxGraphModel>');
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * xml - String that contains the XML data.
\t */
\tparseXml: function()
\t{
\t\tif (window.DOMParser)
\t\t{
\t\t\treturn function(xml)
\t\t\t{
\t\t\t\tvar parser = new DOMParser();
\t\t\t\t
\t\t\t\treturn parser.parseFromString(xml, 'text/xml');
\t\t\t};
\t\t}
\t\telse // IE<=9
\t\t{
\t\t\treturn function(xml)
\t\t\t{
\t\t\t\tvar doc = mxUtils.createMsXmlDocument();
\t\t\t\tdoc.loadXML(xml);
\t\t\t\t
\t\t\t\treturn doc;
\t\t\t};
\t\t}
\t}(),

\t/**
\t * Function: clearSelection
\t * 
\t * Clears the current selection in the page.
\t */
\tclearSelection: function()
\t{
\t\tif (document.selection)
\t\t{
\t\t\treturn function()
\t\t\t{
\t\t\t\tdocument.selection.empty();
\t\t\t};
\t\t}
\t\telse if (window.getSelection)
\t\t{
\t\t\treturn function()
\t\t\t{
\t\t\t\tif (window.getSelection().empty)
\t\t\t\t{
\t\t\t\t\twindow.getSelection().empty();
\t\t\t\t}
\t\t\t\telse if (window.getSelection().removeAllRanges)
\t\t\t\t{
\t\t\t\t\twindow.getSelection().removeAllRanges();
\t\t\t\t}
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function() { };
\t\t}
\t}(),

\t/**
\t * Function: removeWhitespace
\t * 
\t * Removes the sibling text nodes for the given node that only consists
\t * of tabs, newlines and spaces.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node whose siblings should be removed.
\t * before - Optional boolean that specifies the direction of the traversal.
\t */
\tremoveWhitespace: function(node, before)
\t{
\t\tvar tmp = (before) ? node.previousSibling : node.nextSibling;
\t\t
\t\twhile (tmp != null && tmp.nodeType == mxConstants.NODETYPE_TEXT)
\t\t{
\t\t\tvar next = (before) ? tmp.previousSibling : tmp.nextSibling;
\t\t\tvar text = mxUtils.getTextContent(tmp);
\t\t\t
\t\t\tif (mxUtils.trim(text).length == 0)
\t\t\t{
\t\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\t}
\t\t\t
\t\t\ttmp = next;
\t\t}
\t},
\t
\t/**
\t * Function: htmlEntities
\t * 
\t * Replaces characters (less than, greater than, newlines and quotes) with
\t * their HTML entities in the given string and returns the result.
\t * 
\t * Parameters:
\t * 
\t * s - String that contains the characters to be converted.
\t * newline - If newlines should be replaced. Default is true.
\t */
\thtmlEntities: function(s, newline)
\t{
\t\ts = String(s || '');
\t\t
\t\ts = s.replace(/&/g,'&amp;'); // 38 26
\t\ts = s.replace(/\"/g,'&quot;'); // 34 22
\t\ts = s.replace(/\\'/g,'&#39;'); // 39 27
\t\ts = s.replace(/</g,'&lt;'); // 60 3C
\t\ts = s.replace(/>/g,'&gt;'); // 62 3E

\t\tif (newline == null || newline)
\t\t{
\t\t\ts = s.replace(/\\n/g, '&#xa;');
\t\t}
\t\t
\t\treturn s;
\t},
\t
\t/**
\t * Function: isVml
\t * 
\t * Returns true if the given node is in the VML namespace.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node whose tag urn should be checked.
\t */
\tisVml: function(node)
\t{
\t\treturn node != null && node.tagUrn == 'urn:schemas-microsoft-com:vml';
\t},

\t/**
\t * Function: getXml
\t * 
\t * Returns the XML content of the specified node. For Internet Explorer,
\t * all \\r\\n\\t[\\t]* are removed from the XML string and the remaining \\r\\n
\t * are replaced by \\n. All \\n are then replaced with linefeed, or &#xa; if
\t * no linefeed is defined.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to return the XML for.
\t * linefeed - Optional string that linefeeds are converted into. Default is
\t * &#xa;
\t */
\tgetXml: function(node, linefeed)
\t{
\t\tvar xml = '';
\t\t
\t\tif (mxClient.IS_IE || mxClient.IS_IE11)
\t\t{
\t\t\txml = mxUtils.getPrettyXml(node, '', '', '');
\t\t}
\t\telse if (window.XMLSerializer != null)
\t\t{
\t\t\tvar xmlSerializer = new XMLSerializer();
\t\t\txml = xmlSerializer.serializeToString(node);     
\t\t}
\t\telse if (node.xml != null)
\t\t{
\t\t\txml = node.xml.replace(/\\r\\n\\t[\\t]*/g, '').
\t\t\t\treplace(/>\\r\\n/g, '>').
\t\t\t\treplace(/\\r\\n/g, '\\n');
\t\t}

\t\t// Replaces linefeeds with HTML Entities.
\t\tlinefeed = linefeed || '&#xa;';
\t\txml = xml.replace(/\\n/g, linefeed);
\t\t  
\t\treturn xml;
\t},
\t
\t/**
\t * Function: getPrettyXML
\t * 
\t * Returns a pretty printed string that represents the XML tree for the
\t * given node. This method should only be used to print XML for reading,
\t * use <getXml> instead to obtain a string for processing.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to return the XML for.
\t * tab - Optional string that specifies the indentation for one level.
\t * Default is two spaces.
\t * indent - Optional string that represents the current indentation.
\t * Default is an empty string.
\t * newline - Option string that represents a linefeed. Default is '\\n'.
\t */
\tgetPrettyXml: function(node, tab, indent, newline, ns)
\t{
\t\tvar result = [];
\t\t
\t\tif (node != null)
\t\t{
\t\t\ttab = (tab != null) ? tab : '  ';
\t\t\tindent = (indent != null) ? indent : '';
\t\t\tnewline = (newline != null) ? newline : '\\n';
\t\t\t
\t\t\tif (node.namespaceURI != null && node.namespaceURI != ns)
\t\t\t{
\t\t\t\tns = node.namespaceURI;
\t\t\t\t
\t\t\t\tif (node.getAttribute('xmlns') == null)
\t\t\t\t{
\t\t\t\t\tnode.setAttribute('xmlns', node.namespaceURI);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (node.nodeType == mxConstants.NODETYPE_DOCUMENT)
\t\t\t{
\t\t\t\tresult.push(mxUtils.getPrettyXml(node.documentElement, tab, indent, newline, ns));
\t\t\t}
\t\t\telse if (node.nodeType == mxConstants.NODETYPE_DOCUMENT_FRAGMENT)
\t\t\t{
\t\t\t\tvar tmp = node.firstChild;
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\twhile (tmp != null)
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(mxUtils.getPrettyXml(tmp, tab, indent, newline, ns));
\t\t\t\t\t\ttmp = tmp.nextSibling;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (node.nodeType == mxConstants.NODETYPE_COMMENT)
\t\t\t{
\t\t\t\tvar value = mxUtils.getTextContent(node);
\t\t\t\t
\t\t\t\tif (value.length > 0)
\t\t\t\t{
\t\t\t\t\tresult.push(indent + '<!--' + value + '-->' + newline);
\t\t\t\t}
\t\t\t}
\t\t\telse if (node.nodeType == mxConstants.NODETYPE_TEXT)
\t\t\t{
\t\t\t\tvar value = mxUtils.trim(mxUtils.getTextContent(node));
\t\t\t\t
\t\t\t\tif (value.length > 0)
\t\t\t\t{
\t\t\t\t\tresult.push(indent + mxUtils.htmlEntities(value, false) + newline);
\t\t\t\t}
\t\t\t}
\t\t\telse if (node.nodeType == mxConstants.NODETYPE_CDATA)
\t\t\t{
\t\t\t\tvar value = mxUtils.getTextContent(node);
\t\t\t\t
\t\t\t\tif (value.length > 0)
\t\t\t\t{
\t\t\t\t\tresult.push(indent + '<![CDATA[' + value + ']]' + newline);
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.push(indent + '<' + node.nodeName);
\t\t\t\t
\t\t\t\t// Creates the string with the node attributes
\t\t\t\t// and converts all HTML entities in the values
\t\t\t\tvar attrs = node.attributes;
\t\t\t\t
\t\t\t\tif (attrs != null)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < attrs.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar val = mxUtils.htmlEntities(attrs[i].value);
\t\t\t\t\t\tresult.push(' ' + attrs[i].nodeName + '=\"' + val + '\"');
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\t// Recursively creates the XML string for each child
\t\t\t\t// node and appends it here with an indentation
\t\t\t\tvar tmp = node.firstChild;
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\tresult.push('>' + newline);
\t\t\t\t\t
\t\t\t\t\twhile (tmp != null)
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(mxUtils.getPrettyXml(tmp, tab, indent + tab, newline, ns));
\t\t\t\t\t\ttmp = tmp.nextSibling;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tresult.push(indent + '</'+ node.nodeName + '>' + newline);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tresult.push(' />' + newline);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn result.join('');
\t},
\t
\t/**
\t * Function: extractTextWithWhitespace
\t * 
\t * Returns the text content of the specified node.
\t * 
\t * Parameters:
\t * 
\t * elems - DOM nodes to return the text for.
\t */
\textractTextWithWhitespace: function(elems)
\t{
\t    // Known block elements for handling linefeeds (list is not complete)
\t\tvar blocks = ['BLOCKQUOTE', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'OL', 'P', 'PRE', 'TABLE', 'UL'];
\t\tvar ret = [];
\t\t
\t\tfunction doExtract(elts)
\t\t{
\t\t\t// Single break should be ignored
\t\t\tif (elts.length == 1 && (elts[0].nodeName == 'BR' ||
\t\t\t\telts[0].innerHTML == '\\n'))
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t    for (var i = 0; i < elts.length; i++)
\t\t    {
\t\t        var elem = elts[i];

\t\t\t\t// DIV with a br or linefeed forces a linefeed
\t\t\t\tif (elem.nodeName == 'BR' || elem.innerHTML == '\\n' ||
\t\t\t\t\t((elts.length == 1 || i == 0) && (elem.nodeName == 'DIV' &&
\t\t\t\t\telem.innerHTML.toLowerCase() == '<br>')))
\t\t    \t{
\t    \t\t\tret.push('\\n');
\t\t    \t}
\t\t\t\telse
\t\t\t\t{
\t\t\t        if (elem.nodeType === 3 || elem.nodeType === 4)
\t\t\t        {
\t\t\t        \tif (elem.nodeValue.length > 0)
\t\t\t        \t{
\t\t\t        \t\tret.push(elem.nodeValue);
\t\t\t        \t}
\t\t\t        }
\t\t\t        else if (elem.nodeType !== 8 && elem.childNodes.length > 0)
\t\t\t\t\t{
\t\t\t\t\t\tdoExtract(elem.childNodes);
\t\t\t\t\t}
\t\t\t        
\t        \t\tif (i < elts.length - 1 && mxUtils.indexOf(blocks, elts[i + 1].nodeName) >= 0)
\t        \t\t{
\t        \t\t\tret.push('\\n');\t\t
\t        \t\t}
\t\t\t\t}
\t\t    }
\t\t};
\t\t
\t\tdoExtract(elems);
\t    
\t    return ret.join('');
\t},

\t/**
\t * Function: replaceTrailingNewlines
\t * 
\t * Replaces each trailing newline with the given pattern.
\t */
\treplaceTrailingNewlines: function(str, pattern)
\t{
\t\t// LATER: Check is this can be done with a regular expression
\t\tvar postfix = '';
\t\t
\t\twhile (str.length > 0 && str.charAt(str.length - 1) == '\\n')
\t\t{
\t\t\tstr = str.substring(0, str.length - 1);
\t\t\tpostfix += pattern;
\t\t}
\t\t
\t\treturn str + postfix;
\t},

\t/**
\t * Function: getTextContent
\t * 
\t * Returns the text content of the specified node.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to return the text content for.
\t */
\tgetTextContent: function(node)
\t{
\t\t// Only IE10-
\t\tif (mxClient.IS_IE && node.innerText !== undefined)
\t\t{
\t\t\treturn node.innerText;
\t\t}
\t\telse
\t\t{
\t\t\treturn (node != null) ? node[(node.textContent === undefined) ? 'text' : 'textContent'] : '';
\t\t}
\t},
\t
\t/**
\t * Function: setTextContent
\t * 
\t * Sets the text content of the specified node.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to set the text content for.
\t * text - String that represents the text content.
\t */
\tsetTextContent: function(node, text)
\t{
\t\tif (node.innerText !== undefined)
\t\t{
\t\t\tnode.innerText = text;
\t\t}
\t\telse
\t\t{
\t\t\tnode[(node.textContent === undefined) ? 'text' : 'textContent'] = text;
\t\t}
\t},
\t
\t/**
\t * Function: getInnerHtml
\t * 
\t * Returns the inner HTML for the given node as a string or an empty string
\t * if no node was specified. The inner HTML is the text representing all
\t * children of the node, but not the node itself.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to return the inner HTML for.
\t */
\tgetInnerHtml: function()
\t{
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\treturn function(node)
\t\t\t{
\t\t\t\tif (node != null)
\t\t\t\t{
\t\t\t\t\treturn node.innerHTML;
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn '';
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function(node)
\t\t\t{
\t\t\t\tif (node != null)
\t\t\t\t{
\t\t\t\t\tvar serializer = new XMLSerializer();
\t\t\t\t\treturn serializer.serializeToString(node);
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn '';
\t\t\t};
\t\t}
\t}(),

\t/**
\t * Function: getOuterHtml
\t * 
\t * Returns the outer HTML for the given node as a string or an empty
\t * string if no node was specified. The outer HTML is the text representing
\t * all children of the node including the node itself.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to return the outer HTML for.
\t */
\tgetOuterHtml: function()
\t{
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\treturn function(node)
\t\t\t{
\t\t\t\tif (node != null)
\t\t\t\t{
\t\t\t\t\tif (node.outerHTML != null)
\t\t\t\t\t{
\t\t\t\t\t\treturn node.outerHTML;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tvar tmp = [];
\t\t\t\t\t\ttmp.push('<'+node.nodeName);
\t\t\t\t\t\t
\t\t\t\t\t\tvar attrs = node.attributes;
\t\t\t\t\t\t
\t\t\t\t\t\tif (attrs != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tfor (var i = 0; i < attrs.length; i++)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar value = attrs[i].value;
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (value != null && value.length > 0)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttmp.push(' ');
\t\t\t\t\t\t\t\t\ttmp.push(attrs[i].nodeName);
\t\t\t\t\t\t\t\t\ttmp.push('=\"');
\t\t\t\t\t\t\t\t\ttmp.push(value);
\t\t\t\t\t\t\t\t\ttmp.push('\"');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (node.innerHTML.length == 0)
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttmp.push('/>');
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttmp.push('>');
\t\t\t\t\t\t\ttmp.push(node.innerHTML);
\t\t\t\t\t\t\ttmp.push('</'+node.nodeName+'>');
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\treturn tmp.join('');
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn '';
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function(node)
\t\t\t{
\t\t\t\tif (node != null)
\t\t\t\t{
\t\t\t\t\tvar serializer = new XMLSerializer();
\t\t\t\t\treturn serializer.serializeToString(node);
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn '';
\t\t\t};
\t\t}
\t}(),
\t
\t/**
\t * Function: write
\t * 
\t * Creates a text node for the given string and appends it to the given
\t * parent. Returns the text node.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to append the text node to.
\t * text - String representing the text to be added.
\t */
\twrite: function(parent, text)
\t{
\t\tvar doc = parent.ownerDocument;
\t\tvar node = doc.createTextNode(text);
\t\t
\t\tif (parent != null)
\t\t{
\t\t\tparent.appendChild(node);
\t\t}
\t\t
\t\treturn node;
\t},
\t
\t/**
\t * Function: writeln
\t * 
\t * Creates a text node for the given string and appends it to the given
\t * parent with an additional linefeed. Returns the text node.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to append the text node to.
\t * text - String representing the text to be added.
\t */
\twriteln: function(parent, text)
\t{
\t\tvar doc = parent.ownerDocument;
\t\tvar node = doc.createTextNode(text);
\t\t
\t\tif (parent != null)
\t\t{
\t\t\tparent.appendChild(node);
\t\t\tparent.appendChild(document.createElement('br'));
\t\t}
\t\t
\t\treturn node;
\t},
\t
\t/**
\t * Function: br
\t * 
\t * Appends a linebreak to the given parent and returns the linebreak.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to append the linebreak to.
\t */
\tbr: function(parent, count)
\t{
\t\tcount = count || 1;
\t\tvar br = null;
\t\t
\t\tfor (var i = 0; i < count; i++)
\t\t{
\t\t\tif (parent != null)
\t\t\t{
\t\t\t\tbr = parent.ownerDocument.createElement('br');
\t\t\t\tparent.appendChild(br);
\t\t\t}
\t\t}
\t\t
\t\treturn br;
\t},
\t\t
\t/**
\t * Function: button
\t * 
\t * Returns a new button with the given level and function as an onclick
\t * event handler.
\t * 
\t * (code)
\t * document.body.appendChild(mxUtils.button('Test', function(evt)
\t * {
\t *   alert('Hello, World!');
\t * }));
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * label - String that represents the label of the button.
\t * funct - Function to be called if the button is pressed.
\t * doc - Optional document to be used for creating the button. Default is the
\t * current document.
\t */
\tbutton: function(label, funct, doc)
\t{
\t\tdoc = (doc != null) ? doc : document;
\t\t
\t\tvar button = doc.createElement('button');
\t\tmxUtils.write(button, label);

\t\tmxEvent.addListener(button, 'click', function(evt)
\t\t{
\t\t\tfunct(evt);
\t\t});
\t\t
\t\treturn button;
\t},
\t
\t/**
\t * Function: para
\t * 
\t * Appends a new paragraph with the given text to the specified parent and
\t * returns the paragraph.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to append the text node to.
\t * text - String representing the text for the new paragraph.
\t */
\tpara: function(parent, text)
\t{
\t\tvar p = document.createElement('p');
\t\tmxUtils.write(p, text);

\t\tif (parent != null)
\t\t{
\t\t\tparent.appendChild(p);
\t\t}
\t\t
\t\treturn p;
\t},

\t/**
\t * Function: addTransparentBackgroundFilter
\t * 
\t * Adds a transparent background to the filter of the given node. This
\t * background can be used in IE8 standards mode (native IE8 only) to pass
\t * events through the node.
\t */
\taddTransparentBackgroundFilter: function(node)
\t{
\t\tnode.style.filter += 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\\'' +
\t\t\tmxClient.imageBasePath + '/transparent.gif\\', sizingMethod=\\'scale\\')';
\t},

\t/**
\t * Function: linkAction
\t * 
\t * Adds a hyperlink to the specified parent that invokes action on the
\t * specified editor.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to contain the new link.
\t * text - String that is used as the link label.
\t * editor - <mxEditor> that will execute the action.
\t * action - String that defines the name of the action to be executed.
\t * pad - Optional left-padding for the link. Default is 0.
\t */
\tlinkAction: function(parent, text, editor, action, pad)
\t{
\t\treturn mxUtils.link(parent, text, function()
\t\t{
\t\t\teditor.execute(action);
\t\t}, pad);
\t},

\t/**
\t * Function: linkInvoke
\t * 
\t * Adds a hyperlink to the specified parent that invokes the specified
\t * function on the editor passing along the specified argument. The
\t * function name is the name of a function of the editor instance,
\t * not an action name.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to contain the new link.
\t * text - String that is used as the link label.
\t * editor - <mxEditor> instance to execute the function on.
\t * functName - String that represents the name of the function.
\t * arg - Object that represents the argument to the function.
\t * pad - Optional left-padding for the link. Default is 0.
\t */
\tlinkInvoke: function(parent, text, editor, functName, arg, pad)
\t{
\t\treturn mxUtils.link(parent, text, function()
\t\t{
\t\t\teditor[functName](arg);
\t\t}, pad);
\t},
\t
\t/**
\t * Function: link
\t * 
\t * Adds a hyperlink to the specified parent and invokes the given function
\t * when the link is clicked.
\t * 
\t * Parameters:
\t * 
\t * parent - DOM node to contain the new link.
\t * text - String that is used as the link label.
\t * funct - Function to execute when the link is clicked.
\t * pad - Optional left-padding for the link. Default is 0.
\t */
\tlink: function(parent, text, funct, pad)
\t{
\t\tvar a = document.createElement('span');
\t\t
\t\ta.style.color = 'blue';
\t\ta.style.textDecoration = 'underline';
\t\ta.style.cursor = 'pointer';
\t\t
\t\tif (pad != null)
\t\t{
\t\t\ta.style.paddingLeft = pad+'px';
\t\t}
\t\t
\t\tmxEvent.addListener(a, 'click', funct);
\t\tmxUtils.write(a, text);
\t\t
\t\tif (parent != null)
\t\t{
\t\t\tparent.appendChild(a);
\t\t}
\t\t
\t\treturn a;
\t},

\t/**
\t * Function: getDocumentSize
\t * 
\t * Returns the client size for the current document as an <mxRectangle>.
\t */
\tgetDocumentSize: function()
\t{
\t\tvar b = document.body;
\t\tvar d = document.documentElement;
\t\t
\t\ttry
\t\t{
\t\t\treturn new mxRectangle(0, 0, b.clientWidth || d.clientWidth, Math.max(b.clientHeight || 0, d.clientHeight));
\t\t}
\t\tcatch (e)
\t\t{
\t\t\treturn new mxRectangle();
\t\t}
\t},
\t
\t/**
\t * Function: fit
\t * 
\t * Makes sure the given node is inside the visible area of the window. This
\t * is done by setting the left and top in the style. 
\t */
\tfit: function(node)
\t{
\t\tvar ds = mxUtils.getDocumentSize();
\t\tvar left = parseInt(node.offsetLeft);
\t\tvar width = parseInt(node.offsetWidth);
\t\t\t
\t\tvar offset = mxUtils.getDocumentScrollOrigin(node.ownerDocument);
\t\tvar sl = offset.x;
\t\tvar st = offset.y;

\t\tvar b = document.body;
\t\tvar d = document.documentElement;
\t\tvar right = (sl) + ds.width;
\t\t
\t\tif (left + width > right)
\t\t{
\t\t\tnode.style.left = Math.max(sl, right - width) + 'px';
\t\t}
\t\t
\t\tvar top = parseInt(node.offsetTop);
\t\tvar height = parseInt(node.offsetHeight);
\t\t
\t\tvar bottom = st + ds.height;
\t\t
\t\tif (top + height > bottom)
\t\t{
\t\t\tnode.style.top = Math.max(st, bottom - height) + 'px';
\t\t}
\t},

\t/**
\t * Function: load
\t * 
\t * Loads the specified URL *synchronously* and returns the <mxXmlRequest>.
\t * Throws an exception if the file cannot be loaded. See <mxUtils.get> for
\t * an asynchronous implementation.
\t *
\t * Example:
\t * 
\t * (code)
\t * try
\t * {
\t *   var req = mxUtils.load(filename);
\t *   var root = req.getDocumentElement();
\t *   // Process XML DOM...
\t * }
\t * catch (ex)
\t * {
\t *   mxUtils.alert('Cannot load '+filename+': '+ex);
\t * }
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * url - URL to get the data from.
\t */
\tload: function(url)
\t{
\t\tvar req = new mxXmlRequest(url, null, 'GET', false);
\t\treq.send();
\t\t
\t\treturn req;
\t},

\t/**
\t * Function: get
\t * 
\t * Loads the specified URL *asynchronously* and invokes the given functions
\t * depending on the request status. Returns the <mxXmlRequest> in use. Both
\t * functions take the <mxXmlRequest> as the only parameter. See
\t * <mxUtils.load> for a synchronous implementation.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxUtils.get(url, function(req)
\t * {
\t *    var node = req.getDocumentElement();
\t *    // Process XML DOM...
\t * });
\t * (end)
\t * 
\t * So for example, to load a diagram into an existing graph model, the
\t * following code is used.
\t * 
\t * (code)
\t * mxUtils.get(url, function(req)
\t * {
\t *   var node = req.getDocumentElement();
\t *   var dec = new mxCodec(node.ownerDocument);
\t *   dec.decode(node, graph.getModel());
\t * });
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * url - URL to get the data from.
\t * onload - Optional function to execute for a successful response.
\t * onerror - Optional function to execute on error.
\t * binary - Optional boolean parameter that specifies if the request is
\t * binary.
\t * timeout - Optional timeout in ms before calling ontimeout.
\t * ontimeout - Optional function to execute on timeout.
\t * headers - Optional with headers, eg. {'Authorization': 'token xyz'}
\t */
\tget: function(url, onload, onerror, binary, timeout, ontimeout, headers)
\t{
\t\tvar req = new mxXmlRequest(url, null, 'GET');
\t\tvar setRequestHeaders = req.setRequestHeaders;
\t\t
\t\tif (headers)
\t\t{
\t\t\treq.setRequestHeaders = function(request, params)
\t\t\t{
\t\t\t\tsetRequestHeaders.apply(this, arguments);
\t\t\t\t
\t\t\t\tfor (var key in headers)
\t\t\t\t{
\t\t\t\t\trequest.setRequestHeader(key, headers[key]);
\t\t\t\t}
\t\t\t};
\t\t}
\t\t
\t\tif (binary != null)
\t\t{
\t\t\treq.setBinary(binary);
\t\t}
\t\t
\t\treq.send(onload, onerror, timeout, ontimeout);
\t\t
\t\treturn req;
\t},

\t/**
\t * Function: getAll
\t * 
\t * Loads the URLs in the given array *asynchronously* and invokes the given function
\t * if all requests returned with a valid 2xx status. The error handler is invoked
\t * once on the first error or invalid response.
\t *
\t * Parameters:
\t * 
\t * urls - Array of URLs to be loaded.
\t * onload - Callback with array of <mxXmlRequests>.
\t * onerror - Optional function to execute on error.
\t */
\tgetAll: function(urls, onload, onerror)
\t{
\t\tvar remain = urls.length;
\t\tvar result = [];
\t\tvar errors = 0;
\t\tvar err = function()
\t\t{
\t\t\tif (errors == 0 && onerror != null)
\t\t\t{
\t\t\t\tonerror();
\t\t\t}

\t\t\terrors++;
\t\t};
\t\t
\t\tfor (var i = 0; i < urls.length; i++)
\t\t{
\t\t\t(function(url, index)
\t\t\t{
\t\t\t\tmxUtils.get(url, function(req)
\t\t\t\t{
\t\t\t\t\tvar status = req.getStatus();
\t\t\t\t\t
\t\t\t\t\tif (status < 200 || status > 299)
\t\t\t\t\t{
\t\t\t\t\t\terr();
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tresult[index] = req;
\t\t\t\t\t\tremain--;
\t\t\t\t\t\t
\t\t\t\t\t\tif (remain == 0)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tonload(result);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}, err);
\t\t\t})(urls[i], i);
\t\t}
\t\t
\t\tif (remain == 0)
\t\t{
\t\t\tonload(result);\t\t\t
\t\t}
\t},
\t
\t/**
\t * Function: post
\t * 
\t * Posts the specified params to the given URL *asynchronously* and invokes
\t * the given functions depending on the request status. Returns the
\t * <mxXmlRequest> in use. Both functions take the <mxXmlRequest> as the
\t * only parameter. Make sure to use encodeURIComponent for the parameter
\t * values.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxUtils.post(url, 'key=value', function(req)
\t * {
\t * \tmxUtils.alert('Ready: '+req.isReady()+' Status: '+req.getStatus());
\t *  // Process req.getDocumentElement() using DOM API if OK...
\t * });
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * url - URL to get the data from.
\t * params - Parameters for the post request.
\t * onload - Optional function to execute for a successful response.
\t * onerror - Optional function to execute on error.
\t */
\tpost: function(url, params, onload, onerror)
\t{
\t\treturn new mxXmlRequest(url, params).send(onload, onerror);
\t},
\t
\t/**
\t * Function: submit
\t * 
\t * Submits the given parameters to the specified URL using
\t * <mxXmlRequest.simulate> and returns the <mxXmlRequest>.
\t * Make sure to use encodeURIComponent for the parameter
\t * values.
\t * 
\t * Parameters:
\t * 
\t * url - URL to get the data from.
\t * params - Parameters for the form.
\t * doc - Document to create the form in.
\t * target - Target to send the form result to.
\t */
\tsubmit: function(url, params, doc, target)
\t{
\t\treturn new mxXmlRequest(url, params).simulate(doc, target);
\t},
\t
\t/**
\t * Function: loadInto
\t * 
\t * Loads the specified URL *asynchronously* into the specified document,
\t * invoking onload after the document has been loaded. This implementation
\t * does not use <mxXmlRequest>, but the document.load method.
\t * 
\t * Parameters:
\t * 
\t * url - URL to get the data from.
\t * doc - The document to load the URL into.
\t * onload - Function to execute when the URL has been loaded.
\t */
\tloadInto: function(url, doc, onload)
\t{
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\tdoc.onreadystatechange = function ()
\t\t\t{
\t\t\t\tif (doc.readyState == 4)
\t\t\t\t{
\t\t\t\t\tonload();
\t\t\t\t}
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\tdoc.addEventListener('load', onload, false);
\t\t}
\t\t
\t\tdoc.load(url);
\t},
\t
\t/**
\t * Function: getValue
\t * 
\t * Returns the value for the given key in the given associative array or
\t * the given default value if the value is null.
\t * 
\t * Parameters:
\t * 
\t * array - Associative array that contains the value for the key.
\t * key - Key whose value should be returned.
\t * defaultValue - Value to be returned if the value for the given
\t * key is null.
\t */
\tgetValue: function(array, key, defaultValue)
\t{
\t\tvar value = (array != null) ? array[key] : null;

\t\tif (value == null)
\t\t{
\t\t\tvalue = defaultValue;\t\t\t
\t\t}
\t\t
\t\treturn value;
\t},
\t
\t/**
\t * Function: getNumber
\t * 
\t * Returns the numeric value for the given key in the given associative
\t * array or the given default value (or 0) if the value is null. The value
\t * is converted to a numeric value using the Number function.
\t * 
\t * Parameters:
\t * 
\t * array - Associative array that contains the value for the key.
\t * key - Key whose value should be returned.
\t * defaultValue - Value to be returned if the value for the given
\t * key is null. Default is 0.
\t */
\tgetNumber: function(array, key, defaultValue)
\t{
\t\tvar value = (array != null) ? array[key] : null;

\t\tif (value == null)
\t\t{
\t\t\tvalue = defaultValue || 0;\t\t\t
\t\t}
\t\t
\t\treturn Number(value);
\t},
\t
\t/**
\t * Function: getColor
\t * 
\t * Returns the color value for the given key in the given associative
\t * array or the given default value if the value is null. If the value
\t * is <mxConstants.NONE> then null is returned.
\t * 
\t * Parameters:
\t * 
\t * array - Associative array that contains the value for the key.
\t * key - Key whose value should be returned.
\t * defaultValue - Value to be returned if the value for the given
\t * key is null. Default is null.
\t */
\tgetColor: function(array, key, defaultValue)
\t{
\t\tvar value = (array != null) ? array[key] : null;

\t\tif (value == null)
\t\t{
\t\t\tvalue = defaultValue;
\t\t}
\t\telse if (value == mxConstants.NONE)
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\treturn value;
\t},

\t/**
\t * Function: clone
\t * 
\t * Recursively clones the specified object ignoring all fieldnames in the
\t * given array of transient fields. <mxObjectIdentity.FIELD_NAME> is always
\t * ignored by this function.
\t * 
\t * Parameters:
\t * 
\t * obj - Object to be cloned.
\t * transients - Optional array of strings representing the fieldname to be
\t * ignored.
\t * shallow - Optional boolean argument to specify if a shallow clone should
\t * be created, that is, one where all object references are not cloned or,
\t * in other words, one where only atomic (strings, numbers) values are
\t * cloned. Default is false.
\t */
\tclone: function(obj, transients, shallow)
\t{
\t\tshallow = (shallow != null) ? shallow : false;
\t\tvar clone = null;
\t\t
\t\tif (obj != null && typeof(obj.constructor) == 'function')
\t\t{
\t\t\tclone = new obj.constructor();
\t\t\t
\t\t    for (var i in obj)
\t\t    {
\t\t    \tif (i != mxObjectIdentity.FIELD_NAME && (transients == null ||
\t\t    \t\tmxUtils.indexOf(transients, i) < 0))
\t\t    \t{
\t\t\t    \tif (!shallow && typeof(obj[i]) == 'object')
\t\t\t    \t{
\t\t\t            clone[i] = mxUtils.clone(obj[i]);
\t\t\t        }
\t\t\t        else
\t\t\t        {
\t\t\t            clone[i] = obj[i];
\t\t\t        }
\t\t\t\t}
\t\t    }
\t\t}
\t\t
\t    return clone;
\t},

\t/**
\t * Function: equalPoints
\t * 
\t * Compares all mxPoints in the given lists.
\t * 
\t * Parameters:
\t * 
\t * a - Array of <mxPoints> to be compared.
\t * b - Array of <mxPoints> to be compared.
\t */
\tequalPoints: function(a, b)
\t{
\t\tif ((a == null && b != null) || (a != null && b == null) ||
\t\t\t(a != null && b != null && a.length != b.length))
\t\t{
\t\t\treturn false;
\t\t}
\t\telse if (a != null && b != null)
\t\t{
\t\t\tfor (var i = 0; i < a.length; i++)
\t\t\t{
\t\t\t\tif ((a[i] != null && b[i] == null) ||
\t\t\t\t\t(a[i] == null && b[i] != null) ||
\t\t\t\t\t(a[i] != null && b[i] != null &&
\t\t\t\t\t(a[i].x != b[i].x || a[i].y != b[i].y)))
\t\t\t\t{
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn true;
\t},

\t/**
\t * Function: equalEntries
\t * 
\t * Returns true if all properties of the given objects are equal. Values
\t * with NaN are equal to NaN and unequal to any other value.
\t * 
\t * Parameters:
\t * 
\t * a - First object to be compared.
\t * b - Second object to be compared.
\t */
\tequalEntries: function(a, b)
\t{
\t\t// Counts keys in b to check if all values have been compared
\t\tvar count = 0;

\t\tif ((a == null && b != null) || (a != null && b == null) ||
\t\t\t(a != null && b != null && a.length != b.length))
\t\t{
\t\t\treturn false;
\t\t}
\t\telse if (a != null && b != null)
\t\t{
\t\t\tfor (var key in b)
\t\t\t{
\t\t\t\tcount++;
\t\t\t}
\t\t\t
\t\t\tfor (var key in a)
\t\t\t{
\t\t\t\tcount--
\t\t\t\t
\t\t\t\tif ((!mxUtils.isNaN(a[key]) || !mxUtils.isNaN(b[key])) && a[key] != b[key])
\t\t\t\t{
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn count == 0;
\t},
\t
\t/**
\t * Function: removeDuplicates
\t * 
\t * Removes all duplicates from the given array.
\t */
\tremoveDuplicates: function(arr)
\t{
\t\tvar dict = new mxDictionary();
\t\tvar result = [];
\t\t
\t\tfor (var i = 0; i < arr.length; i++)
\t\t{
\t\t\tif (!dict.get(arr[i]))
\t\t\t{
\t\t\t\tresult.push(arr[i]);
\t\t\t\tdict.put(arr[i], true);
\t\t\t}
\t\t}

\t\treturn result;
\t},
\t
\t/**
\t * Function: isNaN
\t *
\t * Returns true if the given value is of type number and isNaN returns true.
\t */
\tisNaN: function(value)
\t{
\t\treturn typeof(value) == 'number' && isNaN(value);
\t},
\t
\t/**
\t * Function: extend
\t *
\t * Assigns a copy of the superclass prototype to the subclass prototype.
\t * Note that this does not call the constructor of the superclass at this
\t * point, the superclass constructor should be called explicitely in the
\t * subclass constructor. Below is an example.
\t * 
\t * (code)
\t * MyGraph = function(container, model, renderHint, stylesheet)
\t * {
\t *   mxGraph.call(this, container, model, renderHint, stylesheet);
\t * }
\t * 
\t * mxUtils.extend(MyGraph, mxGraph);
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * ctor - Constructor of the subclass.
\t * superCtor - Constructor of the superclass.
\t */
\textend: function(ctor, superCtor)
\t{
\t\tvar f = function() {};
\t\tf.prototype = superCtor.prototype;
\t\t
\t\tctor.prototype = new f();
\t\tctor.prototype.constructor = ctor;
\t},

\t/**
\t * Function: toString
\t * 
\t * Returns a textual representation of the specified object.
\t * 
\t * Parameters:
\t * 
\t * obj - Object to return the string representation for.
\t */
\ttoString: function(obj)
\t{
\t    var output = '';
\t    
\t    for (var i in obj)
\t    {
\t    \ttry
\t    \t{
\t\t\t    if (obj[i] == null)
\t\t\t    {
\t\t            output += i + ' = [null]\\n';
\t\t\t    }
\t\t\t    else if (typeof(obj[i]) == 'function')
\t\t\t    {
\t\t            output += i + ' => [Function]\\n';
\t\t        }
\t\t        else if (typeof(obj[i]) == 'object')
\t\t        {
\t\t        \tvar ctor = mxUtils.getFunctionName(obj[i].constructor); 
\t\t            output += i + ' => [' + ctor + ']\\n';
\t\t        }
\t\t        else
\t\t        {
\t\t            output += i + ' = ' + obj[i] + '\\n';
\t\t        }
\t    \t}
\t    \tcatch (e)
\t    \t{
\t    \t\toutput += i + '=' + e.message;
\t    \t}
\t    }
\t    
\t    return output;
\t},

\t/**
\t * Function: toRadians
\t * 
\t * Converts the given degree to radians.
\t */
\ttoRadians: function(deg)
\t{
\t\treturn Math.PI * deg / 180;
\t},

\t/**
\t * Function: toDegree
\t * 
\t * Converts the given radians to degree.
\t */
\ttoDegree: function(rad)
\t{
\t\treturn rad * 180 / Math.PI;
\t},
\t
\t/**
\t * Function: arcToCurves
\t * 
\t * Converts the given arc to a series of curves.
\t */
\tarcToCurves: function(x0, y0, r1, r2, angle, largeArcFlag, sweepFlag, x, y)
\t{
\t\tx -= x0;
\t\ty -= y0;
\t\t
        if (r1 === 0 || r2 === 0) 
        {
        \treturn 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) 
        {
        \tr1 = Math.sqrt(lamda) * r1;
        \tr2 = Math.sqrt(lamda) * r2;
        \tsds = 0;
        }  
        else
        {
        \tvar seif = 1;
            
        \tif (largeArcFlag === fS) 
        \t{
        \t\tseif = -1;
        \t}
            
        \tsds = 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) 
        {
        \tdr -= 2 * Math.PI;
        }
        else if (fS != 0 && dr < 0) 
        {
        \tdr += 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;

\t\tvar 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);
            
            // CurveTo updates x0, y0 so need to restore it
            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);
            
\t\t\tx2 = x3 + dx;
            y2 = y3 + dy;
        }
        
        return result;
\t},

\t/**
\t * Function: getBoundingBox
\t * 
\t * Returns the bounding box for the rotated rectangle.
\t * 
\t * Parameters:
\t * 
\t * rect - <mxRectangle> to be rotated.
\t * angle - Number that represents the angle (in degrees).
\t * cx - Optional <mxPoint> that represents the rotation center. If no
\t * rotation center is given then the center of rect is used.
\t */
\tgetBoundingBox: function(rect, rotation, cx)
\t{
        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;
\t},

\t/**
\t * Function: getRotatedPoint
\t * 
\t * Rotates the given point by the given cos and sin.
\t */
\tgetRotatedPoint: function(pt, cos, sin, c)
\t{
\t\tc = (c != null) ? c : new mxPoint();
\t\tvar x = pt.x - c.x;
\t\tvar y = pt.y - c.y;

\t\tvar x1 = x * cos - y * sin;
\t\tvar y1 = y * cos + x * sin;

\t\treturn new mxPoint(x1 + c.x, y1 + c.y);
\t},
\t
\t/**
\t * Returns an integer mask of the port constraints of the given map
\t * @param dict the style map to determine the port constraints for
\t * @param defaultValue Default value to return if the key is undefined.
\t * @return the mask of port constraint directions
\t * 
\t * Parameters:
\t * 
\t * terminal - <mxCelState> that represents the terminal.
\t * edge - <mxCellState> that represents the edge.
\t * source - Boolean that specifies if the terminal is the source terminal.
\t * defaultValue - Default value to be returned.
\t */
\tgetPortConstraints: function(terminal, edge, source, defaultValue)
\t{
\t\tvar value = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT,
\t\t\tmxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_SOURCE_PORT_CONSTRAINT :
\t\t\t\tmxConstants.STYLE_TARGET_PORT_CONSTRAINT, null));
\t\t
\t\tif (value == null)
\t\t{
\t\t\treturn defaultValue;
\t\t}
\t\telse
\t\t{
\t\t\tvar directions = value.toString();
\t\t\tvar returnValue = mxConstants.DIRECTION_MASK_NONE;
\t\t\tvar constraintRotationEnabled = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT_ROTATION, 0);
\t\t\tvar rotation = 0;
\t\t\t
\t\t\tif (constraintRotationEnabled == 1)
\t\t\t{
\t\t\t\trotation = mxUtils.getValue(terminal.style, mxConstants.STYLE_ROTATION, 0);
\t\t\t}
\t\t\t
\t\t\tvar quad = 0;

\t\t\tif (rotation > 45)
\t\t\t{
\t\t\t\tquad = 1;
\t\t\t\t
\t\t\t\tif (rotation >= 135)
\t\t\t\t{
\t\t\t\t\tquad = 2;
\t\t\t\t}
\t\t\t}
\t\t\telse if (rotation < -45)
\t\t\t{
\t\t\t\tquad = 3;
\t\t\t\t
\t\t\t\tif (rotation <= -135)
\t\t\t\t{
\t\t\t\t\tquad = 2;
\t\t\t\t}
\t\t\t}

\t\t\tif (directions.indexOf(mxConstants.DIRECTION_NORTH) >= 0)
\t\t\t{
\t\t\t\tswitch (quad)
\t\t\t\t{
\t\t\t\t\tcase 0:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_NORTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 1:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_EAST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 2:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_SOUTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 3:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_WEST;
\t\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t\tif (directions.indexOf(mxConstants.DIRECTION_WEST) >= 0)
\t\t\t{
\t\t\t\tswitch (quad)
\t\t\t\t{
\t\t\t\t\tcase 0:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_WEST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 1:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_NORTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 2:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_EAST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 3:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_SOUTH;
\t\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t\tif (directions.indexOf(mxConstants.DIRECTION_SOUTH) >= 0)
\t\t\t{
\t\t\t\tswitch (quad)
\t\t\t\t{
\t\t\t\t\tcase 0:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_SOUTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 1:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_WEST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 2:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_NORTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 3:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_EAST;
\t\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t\tif (directions.indexOf(mxConstants.DIRECTION_EAST) >= 0)
\t\t\t{
\t\t\t\tswitch (quad)
\t\t\t\t{
\t\t\t\t\tcase 0:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_EAST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 1:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_SOUTH;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 2:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_WEST;
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 3:
\t\t\t\t\t\treturnValue |= mxConstants.DIRECTION_MASK_NORTH;
\t\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}

\t\t\treturn returnValue;
\t\t}
\t},
\t
\t/**
\t * Function: reversePortConstraints
\t * 
\t * Reverse the port constraint bitmask. For example, north | east
\t * becomes south | west
\t */
\treversePortConstraints: function(constraint)
\t{
\t\tvar result = 0;
\t\t
\t\tresult = (constraint & mxConstants.DIRECTION_MASK_WEST) << 3;
\t\tresult |= (constraint & mxConstants.DIRECTION_MASK_NORTH) << 1;
\t\tresult |= (constraint & mxConstants.DIRECTION_MASK_SOUTH) >> 1;
\t\tresult |= (constraint & mxConstants.DIRECTION_MASK_EAST) >> 3;
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: findNearestSegment
\t * 
\t * Finds the index of the nearest segment on the given cell state for
\t * the specified coordinate pair.
\t */
\tfindNearestSegment: function(state, x, y)
\t{
\t\tvar index = -1;
\t\t
\t\tif (state.absolutePoints.length > 0)
\t\t{
\t\t\tvar last = state.absolutePoints[0];
\t\t\tvar min = null;
\t\t\t
\t\t\tfor (var i = 1; i < state.absolutePoints.length; i++)
\t\t\t{
\t\t\t\tvar current = state.absolutePoints[i];
\t\t\t\tvar dist = mxUtils.ptSegDistSq(last.x, last.y,
\t\t\t\t\tcurrent.x, current.y, x, y);
\t\t\t\t
\t\t\t\tif (min == null || dist < min)
\t\t\t\t{
\t\t\t\t\tmin = dist;
\t\t\t\t\tindex = i - 1;
\t\t\t\t}

\t\t\t\tlast = current;
\t\t\t}
\t\t}
\t\t
\t\treturn index;
\t},

\t/**
\t * Function: getDirectedBounds
\t * 
\t * Adds the given margins to the given rectangle and rotates and flips the
\t * rectangle according to the respective styles in style.
\t */
\tgetDirectedBounds: function (rect, m, style, flipH, flipV)
\t{
\t\tvar d = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
\t\tflipH = (flipH != null) ? flipH : mxUtils.getValue(style, mxConstants.STYLE_FLIPH, false);
\t\tflipV = (flipV != null) ? flipV : mxUtils.getValue(style, mxConstants.STYLE_FLIPV, false);

\t\tm.x = Math.round(Math.max(0, Math.min(rect.width, m.x)));
\t\tm.y = Math.round(Math.max(0, Math.min(rect.height, m.y)));
\t\tm.width = Math.round(Math.max(0, Math.min(rect.width, m.width)));
\t\tm.height = Math.round(Math.max(0, Math.min(rect.height, m.height)));
\t\t
\t\tif ((flipV && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
\t\t\t(flipH && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
\t\t{
\t\t\tvar tmp = m.x;
\t\t\tm.x = m.width;
\t\t\tm.width = tmp;
\t\t}
\t\t\t
\t\tif ((flipH && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
\t\t\t(flipV && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
\t\t{
\t\t\tvar tmp = m.y;
\t\t\tm.y = m.height;
\t\t\tm.height = tmp;
\t\t}
\t\t
\t\tvar m2 = mxRectangle.fromRectangle(m);
\t\t
\t\tif (d == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\tm2.y = m.x;
\t\t\tm2.x = m.height;
\t\t\tm2.width = m.y;
\t\t\tm2.height = m.width;
\t\t}
\t\telse if (d == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tm2.y = m.height;
\t\t\tm2.x = m.width;
\t\t\tm2.width = m.x;
\t\t\tm2.height = m.y;
\t\t}
\t\telse if (d == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\tm2.y = m.width;
\t\t\tm2.x = m.y;
\t\t\tm2.width = m.height;
\t\t\tm2.height = m.x;
\t\t}
\t\t
\t\treturn new mxRectangle(rect.x + m2.x, rect.y + m2.y, rect.width - m2.width - m2.x, rect.height - m2.height - m2.y);
\t},

\t/**
\t * Function: getPerimeterPoint
\t * 
\t * Returns the intersection between the polygon defined by the array of
\t * points and the line between center and point.
\t */
\tgetPerimeterPoint: function (pts, center, point)
\t{
\t\tvar min = null;
\t\t
\t\tfor (var i = 0; i < pts.length - 1; i++)
\t\t{
\t\t\tvar pt = mxUtils.intersection(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y,
\t\t\t\tcenter.x, center.y, point.x, point.y);
\t\t\t
\t\t\tif (pt != null)
\t\t\t{
\t\t\t\tvar dx = point.x - pt.x;
\t\t\t\tvar dy = point.y - pt.y;
\t\t\t\tvar ip = {p: pt, distSq: dy * dy + dx * dx};
\t\t\t\t
\t\t\t\tif (ip != null && (min == null || min.distSq > ip.distSq))
\t\t\t\t{
\t\t\t\t\tmin = ip;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn (min != null) ? min.p : null;
\t},

\t/**
\t * Function: rectangleIntersectsSegment
\t * 
\t * Returns true if the given rectangle intersects the given segment.
\t * 
\t * Parameters:
\t * 
\t * bounds - <mxRectangle> that represents the rectangle.
\t * p1 - <mxPoint> that represents the first point of the segment.
\t * p2 - <mxPoint> that represents the second point of the segment.
\t */
\trectangleIntersectsSegment: function(bounds, p1, p2)
\t{
\t\tvar top = bounds.y;
\t\tvar left = bounds.x;
\t\tvar bottom = top + bounds.height;
\t\tvar right = left + bounds.width;
\t\t\t
\t\t// Find min and max X for the segment
\t\tvar minX = p1.x;
\t\tvar maxX = p2.x;
\t\t
\t\tif (p1.x > p2.x)
\t\t{
\t\t  minX = p2.x;
\t\t  maxX = p1.x;
\t\t}
\t\t
\t\t// Find the intersection of the segment's and rectangle's x-projections
\t\tif (maxX > right)
\t\t{
\t\t  maxX = right;
\t\t}
\t\t
\t\tif (minX < left)
\t\t{
\t\t  minX = left;
\t\t}
\t\t
\t\tif (minX > maxX) // If their projections do not intersect return false
\t\t{
\t\t  return false;
\t\t}
\t\t
\t\t// Find corresponding min and max Y for min and max X we found before
\t\tvar minY = p1.y;
\t\tvar maxY = p2.y;
\t\tvar dx = p2.x - p1.x;
\t\t
\t\tif (Math.abs(dx) > 0.0000001)
\t\t{
\t\t  var a = (p2.y - p1.y) / dx;
\t\t  var b = p1.y - a * p1.x;
\t\t  minY = a * minX + b;
\t\t  maxY = a * maxX + b;
\t\t}
\t\t
\t\tif (minY > maxY)
\t\t{
\t\t  var tmp = maxY;
\t\t  maxY = minY;
\t\t  minY = tmp;
\t\t}
\t\t
\t\t// Find the intersection of the segment's and rectangle's y-projections
\t\tif (maxY > bottom)
\t\t{
\t\t  maxY = bottom;
\t\t}
\t\t
\t\tif (minY < top)
\t\t{
\t\t  minY = top;
\t\t}
\t\t
\t\tif (minY > maxY) // If Y-projections do not intersect return false
\t\t{
\t\t  return false;
\t\t}
\t\t
\t\treturn true;
\t},
\t
\t/**
\t * Function: contains
\t * 
\t * Returns true if the specified point (x, y) is contained in the given rectangle.
\t * 
\t * Parameters:
\t * 
\t * bounds - <mxRectangle> that represents the area.
\t * x - X-coordinate of the point.
\t * y - Y-coordinate of the point.
\t */
\tcontains: function(bounds, x, y)
\t{
\t\treturn (bounds.x <= x && bounds.x + bounds.width >= x &&
\t\t\t\tbounds.y <= y && bounds.y + bounds.height >= y);
\t},

\t/**
\t * Function: intersects
\t * 
\t * Returns true if the two rectangles intersect.
\t * 
\t * Parameters:
\t * 
\t * a - <mxRectangle> to be checked for intersection.
\t * b - <mxRectangle> to be checked for intersection.
\t */
\tintersects: function(a, b)
\t{
\t\tvar tw = a.width;
\t\tvar th = a.height;
\t\tvar rw = b.width;
\t\tvar rh = b.height;
\t\t
\t\tif (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0)
\t\t{
\t\t    return false;
\t\t}
\t\t
\t\tvar tx = a.x;
\t\tvar ty = a.y;
\t\tvar rx = b.x;
\t\tvar ry = b.y;
\t\t
\t\trw += rx;
\t\trh += ry;
\t\ttw += tx;
\t\tth += ty;

\t\treturn ((rw < rx || rw > tx) &&
\t\t\t(rh < ry || rh > ty) &&
\t\t\t(tw < tx || tw > rx) &&
\t\t\t(th < ty || th > ry));
\t},

\t/**
\t * Function: intersectsHotspot
\t * 
\t * Returns true if the state and the hotspot intersect.
\t * 
\t * Parameters:
\t * 
\t * state - <mxCellState>
\t * x - X-coordinate.
\t * y - Y-coordinate.
\t * hotspot - Optional size of the hostpot.
\t * min - Optional min size of the hostpot.
\t * max - Optional max size of the hostpot.
\t */
\tintersectsHotspot: function(state, x, y, hotspot, min, max)
\t{
\t\thotspot = (hotspot != null) ? hotspot : 1;
\t\tmin = (min != null) ? min : 0;
\t\tmax = (max != null) ? max : 0;
\t\t
\t\tif (hotspot > 0)
\t\t{
\t\t\tvar cx = state.getCenterX();
\t\t\tvar cy = state.getCenterY();
\t\t\tvar w = state.width;
\t\t\tvar h = state.height;
\t\t\t
\t\t\tvar start = mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE) * state.view.scale;

\t\t\tif (start > 0)
\t\t\t{
\t\t\t\tif (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, true))
\t\t\t\t{
\t\t\t\t\tcy = state.y + start / 2;
\t\t\t\t\th = start;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tcx = state.x + start / 2;
\t\t\t\t\tw = start;
\t\t\t\t}
\t\t\t}

\t\t\tw = Math.max(min, w * hotspot);
\t\t\th = Math.max(min, h * hotspot);
\t\t\t
\t\t\tif (max > 0)
\t\t\t{
\t\t\t\tw = Math.min(w, max);
\t\t\t\th = Math.min(h, max);
\t\t\t}
\t\t\t
\t\t\tvar rect = new mxRectangle(cx - w / 2, cy - h / 2, w, h);
\t\t\tvar alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
\t\t\t
\t\t\tif (alpha != 0)
\t\t\t{
\t\t\t\tvar cos = Math.cos(-alpha);
\t\t\t\tvar sin = Math.sin(-alpha);
\t\t\t\tvar cx = new mxPoint(state.getCenterX(), state.getCenterY());
\t\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
\t\t\t\tx = pt.x;
\t\t\t\ty = pt.y;
\t\t\t}
\t\t\t
\t\t\treturn mxUtils.contains(rect, x, y);\t\t\t
\t\t}
\t\t
\t\treturn true;
\t},

\t/**
\t * Function: getOffset
\t * 
\t * Returns the offset for the specified container as an <mxPoint>. The
\t * offset is the distance from the top left corner of the container to the
\t * top left corner of the document.
\t * 
\t * Parameters:
\t * 
\t * container - DOM node to return the offset for.
\t * scollOffset - Optional boolean to add the scroll offset of the document.
\t * Default is false.
\t */
\tgetOffset: function(container, scrollOffset)
\t{
\t\tvar offsetLeft = 0;
\t\tvar offsetTop = 0;
\t\t
\t\t// Ignores document scroll origin for fixed elements
\t\tvar fixed = false;
\t\tvar node = container;
\t\tvar b = document.body;
\t\tvar d = document.documentElement;

\t\twhile (node != null && node != b && node != d && !fixed)
\t\t{
\t\t\tvar style = mxUtils.getCurrentStyle(node);
\t\t\t
\t\t\tif (style != null)
\t\t\t{
\t\t\t\tfixed = fixed || style.position == 'fixed';
\t\t\t}
\t\t\t
\t\t\tnode = node.parentNode;
\t\t}
\t\t
\t\tif (!scrollOffset && !fixed)
\t\t{
\t\t\tvar offset = mxUtils.getDocumentScrollOrigin(container.ownerDocument);
\t\t\toffsetLeft += offset.x;
\t\t\toffsetTop += offset.y;
\t\t}
\t\t
\t\tvar r = container.getBoundingClientRect();
\t\t
\t\tif (r != null)
\t\t{
\t\t\toffsetLeft += r.left;
\t\t\toffsetTop += r.top;
\t\t}
\t\t
\t\treturn new mxPoint(offsetLeft, offsetTop);
\t},

\t/**
\t * Function: getDocumentScrollOrigin
\t * 
\t * Returns the scroll origin of the given document or the current document
\t * if no document is given.
\t */
\tgetDocumentScrollOrigin: function(doc)
\t{
\t\tif (mxClient.IS_QUIRKS)
\t\t{
\t\t\treturn new mxPoint(doc.body.scrollLeft, doc.body.scrollTop);
\t\t}
\t\telse
\t\t{
\t\t\tvar wnd = doc.defaultView || doc.parentWindow;
\t\t\t
\t\t\tvar x = (wnd != null && window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
\t\t\tvar y = (wnd != null && window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
\t\t\t
\t\t\treturn new mxPoint(x, y);
\t\t}
\t},
\t
\t/**
\t * Function: getScrollOrigin
\t * 
\t * Returns the top, left corner of the viewrect as an <mxPoint>.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node whose scroll origin should be returned.
\t * includeAncestors - Whether the scroll origin of the ancestors should be
\t * included. Default is false.
\t * includeDocument - Whether the scroll origin of the document should be
\t * included. Default is true.
\t */
\tgetScrollOrigin: function(node, includeAncestors, includeDocument)
\t{
\t\tincludeAncestors = (includeAncestors != null) ? includeAncestors : false;
\t\tincludeDocument = (includeDocument != null) ? includeDocument : true;
\t\t
\t\tvar doc = (node != null) ? node.ownerDocument : document;
\t\tvar b = doc.body;
\t\tvar d = doc.documentElement;
\t\tvar result = new mxPoint();
\t\tvar fixed = false;

\t\twhile (node != null && node != b && node != d)
\t\t{
\t\t\tif (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop))
\t\t\t{
\t\t\t\tresult.x += node.scrollLeft;
\t\t\t\tresult.y += node.scrollTop;
\t\t\t}
\t\t\t
\t\t\tvar style = mxUtils.getCurrentStyle(node);
\t\t\t
\t\t\tif (style != null)
\t\t\t{
\t\t\t\tfixed = fixed || style.position == 'fixed';
\t\t\t}

\t\t\tnode = (includeAncestors) ? node.parentNode : null;
\t\t}

\t\tif (!fixed && includeDocument)
\t\t{
\t\t\tvar origin = mxUtils.getDocumentScrollOrigin(doc);

\t\t\tresult.x += origin.x;
\t\t\tresult.y += origin.y;
\t\t}
\t\t
\t\treturn result;
\t},

\t/**
\t * Function: convertPoint
\t * 
\t * Converts the specified point (x, y) using the offset of the specified
\t * container and returns a new <mxPoint> with the result.
\t * 
\t * (code)
\t * var pt = mxUtils.convertPoint(graph.container,
\t *   mxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * container - DOM node to use for the offset.
\t * x - X-coordinate of the point to be converted.
\t * y - Y-coordinate of the point to be converted.
\t */
\tconvertPoint: function(container, x, y)
\t{
\t\tvar origin = mxUtils.getScrollOrigin(container, false);
\t\tvar offset = mxUtils.getOffset(container);

\t\toffset.x -= origin.x;
\t\toffset.y -= origin.y;
\t\t
\t\treturn new mxPoint(x - offset.x, y - offset.y);
\t},
\t
\t/**
\t * Function: ltrim
\t * 
\t * Strips all whitespaces from the beginning of the string. Without the
\t * second parameter, this will trim these characters:
\t * 
\t * - \" \" (ASCII 32 (0x20)), an ordinary space
\t * - \"\\t\" (ASCII 9 (0x09)), a tab
\t * - \"\\n\" (ASCII 10 (0x0A)), a new line (line feed)
\t * - \"\\r\" (ASCII 13 (0x0D)), a carriage return
\t * - \"\\0\" (ASCII 0 (0x00)), the NUL-byte
\t * - \"\\x0B\" (ASCII 11 (0x0B)), a vertical tab
\t */
\tltrim: function(str, chars)
\t{
\t\tchars = chars || \"\\\\s\";
\t\t
\t\treturn (str != null) ? str.replace(new RegExp(\"^[\" + chars + \"]+\", \"g\"), \"\") : null;
\t},
\t
\t/**
\t * Function: rtrim
\t * 
\t * Strips all whitespaces from the end of the string. Without the second
\t * parameter, this will trim these characters:
\t * 
\t * - \" \" (ASCII 32 (0x20)), an ordinary space
\t * - \"\\t\" (ASCII 9 (0x09)), a tab
\t * - \"\\n\" (ASCII 10 (0x0A)), a new line (line feed)
\t * - \"\\r\" (ASCII 13 (0x0D)), a carriage return
\t * - \"\\0\" (ASCII 0 (0x00)), the NUL-byte
\t * - \"\\x0B\" (ASCII 11 (0x0B)), a vertical tab
\t */
\trtrim: function(str, chars)
\t{
\t\tchars = chars || \"\\\\s\";
\t\t
\t\treturn (str != null) ? str.replace(new RegExp(\"[\" + chars + \"]+\$\", \"g\"), \"\") : null;
\t},
\t
\t/**
\t * Function: trim
\t * 
\t * Strips all whitespaces from both end of the string.
\t * Without the second parameter, Javascript function will trim these
\t * characters:
\t * 
\t * - \" \" (ASCII 32 (0x20)), an ordinary space
\t * - \"\\t\" (ASCII 9 (0x09)), a tab
\t * - \"\\n\" (ASCII 10 (0x0A)), a new line (line feed)
\t * - \"\\r\" (ASCII 13 (0x0D)), a carriage return
\t * - \"\\0\" (ASCII 0 (0x00)), the NUL-byte
\t * - \"\\x0B\" (ASCII 11 (0x0B)), a vertical tab
\t */
\ttrim: function(str, chars)
\t{
\t\treturn mxUtils.ltrim(mxUtils.rtrim(str, chars), chars);
\t},
\t
\t/**
\t * Function: isNumeric
\t * 
\t * Returns true if the specified value is numeric, that is, if it is not
\t * null, not an empty string, not a HEX number and isNaN returns false.
\t * 
\t * Parameters:
\t * 
\t * n - String representing the possibly numeric value.
\t */
\tisNumeric: function(n)
\t{
\t\treturn !isNaN(parseFloat(n)) && isFinite(n) && (typeof(n) != 'string' || n.toLowerCase().indexOf('0x') < 0);
\t},

\t/**
\t * Function: isInteger
\t * 
\t * Returns true if the given value is an valid integer number.
\t * 
\t * Parameters:
\t * 
\t * n - String representing the possibly numeric value.
\t */
\tisInteger: function(n)
\t{
\t\treturn String(parseInt(n)) === String(n);
\t},

\t/**
\t * Function: mod
\t * 
\t * Returns the remainder of division of n by m. You should use this instead
\t * of the built-in operation as the built-in operation does not properly
\t * handle negative numbers.
\t */
\tmod: function(n, m)
\t{
\t\treturn ((n % m) + m) % m;
\t},

\t/**
\t * Function: intersection
\t * 
\t * Returns the intersection of two lines as an <mxPoint>.
\t * 
\t * Parameters:
\t * 
\t * x0 - X-coordinate of the first line's startpoint.
\t * y0 - X-coordinate of the first line's startpoint.
\t * x1 - X-coordinate of the first line's endpoint.
\t * y1 - Y-coordinate of the first line's endpoint.
\t * x2 - X-coordinate of the second line's startpoint.
\t * y2 - Y-coordinate of the second line's startpoint.
\t * x3 - X-coordinate of the second line's endpoint.
\t * y3 - Y-coordinate of the second line's endpoint.
\t */
\tintersection: function (x0, y0, x1, y1, x2, y2, x3, y3)
\t{
\t\tvar denom = ((y3 - y2) * (x1 - x0)) - ((x3 - x2) * (y1 - y0));
\t\tvar nume_a = ((x3 - x2) * (y0 - y2)) - ((y3 - y2) * (x0 - x2));
\t\tvar nume_b = ((x1 - x0) * (y0 - y2)) - ((y1 - y0) * (x0 - x2));

\t\tvar ua = nume_a / denom;
\t\tvar ub = nume_b / denom;
\t\t
\t\tif(ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0)
\t\t{
\t\t\t// Get the intersection point
\t\t\tvar x = x0 + ua * (x1 - x0);
\t\t\tvar y = y0 + ua * (y1 - y0);
\t\t\t
\t\t\treturn new mxPoint(x, y);
\t\t}
\t\t
\t\t// No intersection
\t\treturn null;
\t},
\t
\t/**
\t * Function: ptSegDistSq
\t * 
\t * Returns the square distance between a segment and a point. To get the
\t * distance between a point and a line (with infinite length) use
\t * <mxUtils.ptLineDist>.
\t * 
\t * Parameters:
\t * 
\t * x1 - X-coordinate of the startpoint of the segment.
\t * y1 - Y-coordinate of the startpoint of the segment.
\t * x2 - X-coordinate of the endpoint of the segment.
\t * y2 - Y-coordinate of the endpoint of the segment.
\t * px - X-coordinate of the point.
\t * py - Y-coordinate of the point.
\t */
\tptSegDistSq: function(x1, y1, x2, y2, px, py)
    {
\t\tx2 -= x1;
\t\ty2 -= y1;

\t\tpx -= x1;
\t\tpy -= y1;

\t\tvar dotprod = px * x2 + py * y2;
\t\tvar projlenSq;

\t\tif (dotprod <= 0.0)
\t\t{
\t\t    projlenSq = 0.0;
\t\t}
\t\telse
\t\t{
\t\t    px = x2 - px;
\t\t    py = y2 - py;
\t\t    dotprod = px * x2 + py * y2;

\t\t    if (dotprod <= 0.0)
\t\t    {
\t\t\t\tprojlenSq = 0.0;
\t\t    }
\t\t    else
\t\t    {
\t\t\t\tprojlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
\t\t    }
\t\t}

\t\tvar lenSq = px * px + py * py - projlenSq;
\t\t
\t\tif (lenSq < 0)
\t\t{
\t\t    lenSq = 0;
\t\t}
\t\t
\t\treturn lenSq;
    },
\t
\t/**
\t * Function: ptLineDist
\t * 
\t * Returns the distance between a line defined by two points and a point.
\t * To get the distance between a point and a segment (with a specific
\t * length) use <mxUtils.ptSeqDistSq>.
\t * 
\t * Parameters:
\t * 
\t * x1 - X-coordinate of point 1 of the line.
\t * y1 - Y-coordinate of point 1 of the line.
\t * x2 - X-coordinate of point 1 of the line.
\t * y2 - Y-coordinate of point 1 of the line.
\t * px - X-coordinate of the point.
\t * py - Y-coordinate of the point.
\t */
    ptLineDist: function(x1, y1, x2, y2, px, py)
    {
\t\treturn Math.abs((y2 - y1) * px - (x2 - x1) * py + x2 * y1 - y2 * x1) /
\t\t\tMath.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
    },
    \t
\t/**
\t * Function: relativeCcw
\t * 
\t * Returns 1 if the given point on the right side of the segment, 0 if its
\t * on the segment, and -1 if the point is on the left side of the segment.
\t * 
\t * Parameters:
\t * 
\t * x1 - X-coordinate of the startpoint of the segment.
\t * y1 - Y-coordinate of the startpoint of the segment.
\t * x2 - X-coordinate of the endpoint of the segment.
\t * y2 - Y-coordinate of the endpoint of the segment.
\t * px - X-coordinate of the point.
\t * py - Y-coordinate of the point.
\t */
\trelativeCcw: function(x1, y1, x2, y2, px, py)
    {
\t\tx2 -= x1;
\t\ty2 -= y1;
\t\tpx -= x1;
\t\tpy -= y1;
\t\tvar ccw = px * y2 - py * x2;
\t\t
\t\tif (ccw == 0.0)
\t\t{
\t\t    ccw = px * x2 + py * y2;
\t\t    
\t\t    if (ccw > 0.0)
\t\t    {
\t\t\t\tpx -= x2;
\t\t\t\tpy -= y2;
\t\t\t\tccw = px * x2 + py * y2;
\t\t\t\t
\t\t\t\tif (ccw < 0.0)
\t\t\t\t{
\t\t\t\t    ccw = 0.0;
\t\t\t\t}
\t\t    }
\t\t}
\t\t
\t\treturn (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
    },
    
\t/**
\t * Function: animateChanges
\t * 
\t * See <mxEffects.animateChanges>. This is for backwards compatibility and
\t * will be removed later.
\t */
\tanimateChanges: function(graph, changes)
\t{
\t\t// LATER: Deprecated, remove this function
    \tmxEffects.animateChanges.apply(this, arguments);
\t},
    
\t/**
\t * Function: cascadeOpacity
\t * 
\t * See <mxEffects.cascadeOpacity>. This is for backwards compatibility and
\t * will be removed later.
\t */
    cascadeOpacity: function(graph, cell, opacity)
\t{
\t\tmxEffects.cascadeOpacity.apply(this, arguments);
\t},

\t/**
\t * Function: fadeOut
\t * 
\t * See <mxEffects.fadeOut>. This is for backwards compatibility and
\t * will be removed later.
\t */
\tfadeOut: function(node, from, remove, step, delay, isEnabled)
\t{
\t\tmxEffects.fadeOut.apply(this, arguments);
\t},
\t
\t/**
\t * Function: setOpacity
\t * 
\t * Sets the opacity of the specified DOM node to the given value in %.
\t * 
\t * Parameters:
\t * 
\t * node - DOM node to set the opacity for.
\t * value - Opacity in %. Possible values are between 0 and 100.
\t */
\tsetOpacity: function(node, value)
\t{
\t\tif (mxUtils.isVml(node))
\t\t{
\t    \tif (value >= 100)
\t    \t{
\t    \t\tnode.style.filter = '';
\t    \t}
\t    \telse
\t    \t{
\t    \t\t// TODO: Why is the division by 5 needed in VML?
\t\t\t    node.style.filter = 'alpha(opacity=' + (value/5) + ')';
\t    \t}
\t\t}
\t\telse if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9))
\t    {
\t    \tif (value >= 100)
\t    \t{
\t    \t\tnode.style.filter = '';
\t    \t}
\t    \telse
\t    \t{
\t\t\t    node.style.filter = 'alpha(opacity=' + value + ')';
\t    \t}
\t\t}
\t\telse
\t\t{
\t\t    node.style.opacity = (value / 100);
\t\t}
\t},

\t/**
\t * Function: createImage
\t * 
\t * Creates and returns an image (IMG node) or VML image (v:image) in IE6 in
\t * quirks mode.
\t * 
\t * Parameters:
\t * 
\t * src - URL that points to the image to be displayed.
\t */
\tcreateImage: function(src)
\t{
        var imageNode = null;
        
\t\tif (mxClient.IS_IE6 && document.compatMode != 'CSS1Compat')
\t\t{
        \timageNode = document.createElement(mxClient.VML_PREFIX + ':image');
        \timageNode.setAttribute('src', src);
        \timageNode.style.borderStyle = 'none';
        }
\t\telse
\t\t{
\t\t\timageNode = document.createElement('img');
\t\t\timageNode.setAttribute('src', src);
\t\t\timageNode.setAttribute('border', '0');
\t\t}
\t\t
\t\treturn imageNode;
\t},

\t/**
\t * Function: sortCells
\t * 
\t * Sorts the given cells according to the order in the cell hierarchy.
\t * Ascending is optional and defaults to true.
\t */
\tsortCells: function(cells, ascending)
\t{
\t\tascending = (ascending != null) ? ascending : true;
\t\tvar lookup = new mxDictionary();
\t\tcells.sort(function(o1, o2)
\t\t{
\t\t\tvar p1 = lookup.get(o1);
\t\t\t
\t\t\tif (p1 == null)
\t\t\t{
\t\t\t\tp1 = mxCellPath.create(o1).split(mxCellPath.PATH_SEPARATOR);
\t\t\t\tlookup.put(o1, p1);
\t\t\t}
\t\t\t
\t\t\tvar p2 = lookup.get(o2);
\t\t\t
\t\t\tif (p2 == null)
\t\t\t{
\t\t\t\tp2 = mxCellPath.create(o2).split(mxCellPath.PATH_SEPARATOR);
\t\t\t\tlookup.put(o2, p2);
\t\t\t}
\t\t\t
\t\t\tvar comp = mxCellPath.compare(p1, p2);
\t\t\t
\t\t\treturn (comp == 0) ? 0 : (((comp > 0) == ascending) ? 1 : -1);
\t\t});
\t\t
\t\treturn cells;
\t},

\t/**
\t * Function: getStylename
\t * 
\t * Returns the stylename in a style of the form [(stylename|key=value);] or
\t * an empty string if the given style does not contain a stylename.
\t * 
\t * Parameters:
\t * 
\t * style - String of the form [(stylename|key=value);].
\t */
\tgetStylename: function(style)
\t{
\t\tif (style != null)
\t\t{
\t\t\tvar pairs = style.split(';');
\t\t\tvar stylename = pairs[0];
\t\t\t
\t\t\tif (stylename.indexOf('=') < 0)
\t\t\t{
\t\t\t\treturn stylename;
\t\t\t}
\t\t}
\t\t\t\t
\t\treturn '';
\t},

\t/**
\t * Function: getStylenames
\t * 
\t * Returns the stylenames in a style of the form [(stylename|key=value);]
\t * or an empty array if the given style does not contain any stylenames.
\t * 
\t * Parameters:
\t * 
\t * style - String of the form [(stylename|key=value);].
\t */
\tgetStylenames: function(style)
\t{
\t\tvar result = [];
\t\t
\t\tif (style != null)
\t\t{
\t\t\tvar pairs = style.split(';');
\t\t\t
\t\t\tfor (var i = 0; i < pairs.length; i++)
\t\t\t{
\t\t\t\tif (pairs[i].indexOf('=') < 0)
\t\t\t\t{
\t\t\t\t\tresult.push(pairs[i]);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t\t\t
\t\treturn result;
\t},

\t/**
\t * Function: indexOfStylename
\t * 
\t * Returns the index of the given stylename in the given style. This
\t * returns -1 if the given stylename does not occur (as a stylename) in the
\t * given style, otherwise it returns the index of the first character.
\t */
\tindexOfStylename: function(style, stylename)
\t{
\t\tif (style != null && stylename != null)
\t\t{
\t\t\tvar tokens = style.split(';');
\t\t\tvar pos = 0;
\t\t\t
\t\t\tfor (var i = 0; i < tokens.length; i++)
\t\t\t{
\t\t\t\tif (tokens[i] == stylename)
\t\t\t\t{
\t\t\t\t\treturn pos;
\t\t\t\t}
\t\t\t\t
\t\t\t\tpos += tokens[i].length + 1;
\t\t\t}
\t\t}

\t\treturn -1;
\t},
\t
\t/**
\t * Function: addStylename
\t * 
\t * Adds the specified stylename to the given style if it does not already
\t * contain the stylename.
\t */
\taddStylename: function(style, stylename)
\t{
\t\tif (mxUtils.indexOfStylename(style, stylename) < 0)
\t\t{
\t\t\tif (style == null)
\t\t\t{
\t\t\t\tstyle = '';
\t\t\t}
\t\t\telse if (style.length > 0 && style.charAt(style.length - 1) != ';')
\t\t\t{
\t\t\t\tstyle += ';';
\t\t\t}
\t\t\t
\t\t\tstyle += stylename;
\t\t}
\t\t
\t\treturn style;
\t},
\t
\t/**
\t * Function: removeStylename
\t * 
\t * Removes all occurrences of the specified stylename in the given style
\t * and returns the updated style. Trailing semicolons are not preserved.
\t */
\tremoveStylename: function(style, stylename)
\t{
\t\tvar result = [];
\t\t
\t\tif (style != null)
\t\t{
\t\t\tvar tokens = style.split(';');
\t\t\t
\t\t\tfor (var i = 0; i < tokens.length; i++)
\t\t\t{
\t\t\t\tif (tokens[i] != stylename)
\t\t\t\t{
\t\t\t\t\tresult.push(tokens[i]);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn result.join(';');
\t},
\t
\t/**
\t * Function: removeAllStylenames
\t * 
\t * Removes all stylenames from the given style and returns the updated
\t * style.
\t */
\tremoveAllStylenames: function(style)
\t{
\t\tvar result = [];
\t\t
\t\tif (style != null)
\t\t{
\t\t\tvar tokens = style.split(';');
\t\t\t
\t\t\tfor (var i = 0; i < tokens.length; i++)
\t\t\t{
\t\t\t\t// Keeps the key, value assignments
\t\t\t\tif (tokens[i].indexOf('=') >= 0)
\t\t\t\t{
\t\t\t\t\tresult.push(tokens[i]);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn result.join(';');
\t},

\t/**
\t * Function: setCellStyles
\t * 
\t * Assigns the value for the given key in the styles of the given cells, or
\t * removes the key from the styles if the value is null.
\t * 
\t * Parameters:
\t * 
\t * model - <mxGraphModel> to execute the transaction in.
\t * cells - Array of <mxCells> to be updated.
\t * key - Key of the style to be changed.
\t * value - New value for the given key.
\t */
\tsetCellStyles: function(model, cells, key, value)
\t{
\t\tif (cells != null && cells.length > 0)
\t\t{
\t\t\tmodel.beginUpdate();
\t\t\ttry
\t\t\t{
\t\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t\t{
\t\t\t\t\tif (cells[i] != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar style = mxUtils.setStyle(model.getStyle(cells[i]), key, value);
\t\t\t\t\t\tmodel.setStyle(cells[i], style);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\tfinally
\t\t\t{
\t\t\t\tmodel.endUpdate();
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: setStyle
\t * 
\t * Adds or removes the given key, value pair to the style and returns the
\t * new style. If value is null or zero length then the key is removed from
\t * the style. This is for cell styles, not for CSS styles.
\t * 
\t * Parameters:
\t * 
\t * style - String of the form [(stylename|key=value);].
\t * key - Key of the style to be changed.
\t * value - New value for the given key.
\t */
\tsetStyle: function(style, key, value)
\t{
\t\tvar isValue = value != null && (typeof(value.length) == 'undefined' || value.length > 0);
\t\t
\t\tif (style == null || style.length == 0)
\t\t{
\t\t\tif (isValue)
\t\t\t{
\t\t\t\tstyle = key + '=' + value + ';';
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (style.substring(0, key.length + 1) == key + '=')
\t\t\t{
\t\t\t\tvar next = style.indexOf(';');
\t\t\t\t
\t\t\t\tif (isValue)
\t\t\t\t{
\t\t\t\t\tstyle = key + '=' + value + ((next < 0) ? ';' : style.substring(next));
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tstyle = (next < 0 || next == style.length - 1) ? '' : style.substring(next + 1);
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar index = style.indexOf(';' + key + '=');
\t\t\t\t
\t\t\t\tif (index < 0)
\t\t\t\t{
\t\t\t\t\tif (isValue)
\t\t\t\t\t{
\t\t\t\t\t\tvar sep = (style.charAt(style.length - 1) == ';') ? '' : ';';
\t\t\t\t\t\tstyle = style + sep + key + '=' + value + ';';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar next = style.indexOf(';', index + 1);
\t\t\t\t\t
\t\t\t\t\tif (isValue)
\t\t\t\t\t{
\t\t\t\t\t\tstyle = style.substring(0, index + 1) + key + '=' + value + ((next < 0) ? ';' : style.substring(next));
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tstyle = style.substring(0, index) + ((next < 0) ? ';' : style.substring(next));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn style;
\t},

\t/**
\t * Function: setCellStyleFlags
\t * 
\t * Sets or toggles the flag bit for the given key in the cell's styles.
\t * If value is null then the flag is toggled.
\t * 
\t * Example:
\t * 
\t * (code)
\t * var cells = graph.getSelectionCells();
\t * mxUtils.setCellStyleFlags(graph.model,
\t * \t\t\tcells,
\t * \t\t\tmxConstants.STYLE_FONTSTYLE,
\t * \t\t\tmxConstants.FONT_BOLD);
\t * (end)
\t * 
\t * Toggles the bold font style.
\t * 
\t * Parameters:
\t * 
\t * model - <mxGraphModel> that contains the cells.
\t * cells - Array of <mxCells> to change the style for.
\t * key - Key of the style to be changed.
\t * flag - Integer for the bit to be changed.
\t * value - Optional boolean value for the flag.
\t */
\tsetCellStyleFlags: function(model, cells, key, flag, value)
\t{
\t\tif (cells != null && cells.length > 0)
\t\t{
\t\t\tmodel.beginUpdate();
\t\t\ttry
\t\t\t{
\t\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t\t{
\t\t\t\t\tif (cells[i] != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar style = mxUtils.setStyleFlag(
\t\t\t\t\t\t\tmodel.getStyle(cells[i]),
\t\t\t\t\t\t\tkey, flag, value);
\t\t\t\t\t\tmodel.setStyle(cells[i], style);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\tfinally
\t\t\t{
\t\t\t\tmodel.endUpdate();
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: setStyleFlag
\t * 
\t * Sets or removes the given key from the specified style and returns the
\t * new style. If value is null then the flag is toggled.
\t * 
\t * Parameters:
\t * 
\t * style - String of the form [(stylename|key=value);].
\t * key - Key of the style to be changed.
\t * flag - Integer for the bit to be changed.
\t * value - Optional boolean value for the given flag.
\t */
\tsetStyleFlag: function(style, key, flag, value)
\t{
\t\tif (style == null || style.length == 0)
\t\t{
\t\t\tif (value || value == null)
\t\t\t{
\t\t\t\tstyle = key+'='+flag;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tstyle = key+'=0';
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar index = style.indexOf(key+'=');
\t\t\t
\t\t\tif (index < 0)
\t\t\t{
\t\t\t\tvar sep = (style.charAt(style.length-1) == ';') ? '' : ';';

\t\t\t\tif (value || value == null)
\t\t\t\t{
\t\t\t\t\tstyle = style + sep + key + '=' + flag;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tstyle = style + sep + key + '=0';
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar cont = style.indexOf(';', index);
\t\t\t\tvar tmp = '';
\t\t\t\t
\t\t\t\tif (cont < 0)
\t\t\t\t{
\t\t\t\t\ttmp  = style.substring(index+key.length+1);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttmp = style.substring(index+key.length+1, cont);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (value == null)
\t\t\t\t{
\t\t\t\t\ttmp = parseInt(tmp) ^ flag;
\t\t\t\t}
\t\t\t\telse if (value)
\t\t\t\t{
\t\t\t\t\ttmp = parseInt(tmp) | flag;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttmp = parseInt(tmp) & ~flag;
\t\t\t\t}
\t\t\t\t
\t\t\t\tstyle = style.substring(0, index) + key + '=' + tmp +
\t\t\t\t\t((cont >= 0) ? style.substring(cont) : '');
\t\t\t}
\t\t}
\t\t
\t\treturn style;
\t},
\t
\t/**
\t * Function: getAlignmentAsPoint
\t * 
\t * Returns an <mxPoint> that represents the horizontal and vertical alignment
\t * for numeric computations. X is -0.5 for center, -1 for right and 0 for
\t * left alignment. Y is -0.5 for middle, -1 for bottom and 0 for top
\t * alignment. Default values for missing arguments is top, left.
\t */
\tgetAlignmentAsPoint: function(align, valign)
\t{
\t\tvar dx = -0.5;
\t\tvar dy = -0.5;
\t\t
\t\t// Horizontal alignment
\t\tif (align == mxConstants.ALIGN_LEFT)
\t\t{
\t\t\tdx = 0;
\t\t}
\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t{
\t\t\tdx = -1;
\t\t}

\t\t// Vertical alignment
\t\tif (valign == mxConstants.ALIGN_TOP)
\t\t{
\t\t\tdy = 0;
\t\t}
\t\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t\t{
\t\t\tdy = -1;
\t\t}
\t\t
\t\treturn new mxPoint(dx, dy);
\t},
\t
\t/**
\t * Function: getSizeForString
\t * 
\t * Returns an <mxRectangle> with the size (width and height in pixels) of
\t * the given string. The string may contain HTML markup. Newlines should be
\t * converted to <br> before calling this method. The caller is responsible
\t * for sanitizing the HTML markup.
\t * 
\t * Example:
\t * 
\t * (code)
\t * var label = graph.getLabel(cell).replace(/\\n/g, \"<br>\");
\t * var size = graph.getSizeForString(label);
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * text - String whose size should be returned.
\t * fontSize - Integer that specifies the font size in pixels. Default is
\t * <mxConstants.DEFAULT_FONTSIZE>.
\t * fontFamily - String that specifies the name of the font family. Default
\t * is <mxConstants.DEFAULT_FONTFAMILY>.
\t * textWidth - Optional width for text wrapping.
\t * fontStyle - Optional font style.
\t */
\tgetSizeForString: function(text, fontSize, fontFamily, textWidth, fontStyle)
\t{
\t\tfontSize = (fontSize != null) ? fontSize : mxConstants.DEFAULT_FONTSIZE;
\t\tfontFamily = (fontFamily != null) ? fontFamily : mxConstants.DEFAULT_FONTFAMILY;
\t\tvar div = document.createElement('div');
\t\t
\t\t// Sets the font size and family
\t\tdiv.style.fontFamily = fontFamily;
\t\tdiv.style.fontSize = Math.round(fontSize) + 'px';
\t\tdiv.style.lineHeight = Math.round(fontSize * mxConstants.LINE_HEIGHT) + 'px';
\t\t
\t\t// Sets the font style
\t\tif (fontStyle != null)
\t\t{
\t\t\tif ((fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t\t\t{
\t\t\t\tdiv.style.fontWeight = 'bold';
\t\t\t}
\t\t\t
\t\t\tif ((fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t\t\t{
\t\t\t\tdiv.style.fontStyle = 'italic';
\t\t\t}
\t\t\t
\t\t\tvar txtDecor = [];
\t\t\t
\t\t\tif ((fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t\t\t{
\t\t\t\ttxtDecor.push('underline');
\t\t\t}
\t\t\t
\t\t\tif ((fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t\t\t{
\t\t\t\ttxtDecor.push('line-through');
\t\t\t}
\t\t\t
\t\t\tif (txtDecor.length > 0)
\t\t\t{
\t\t\t\tdiv.style.textDecoration = txtDecor.join(' ');
\t\t\t}
\t\t}
\t\t
\t\t// Disables block layout and outside wrapping and hides the div
\t\tdiv.style.position = 'absolute';
\t\tdiv.style.visibility = 'hidden';
\t\tdiv.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
\t\tdiv.style.zoom = '1';
\t\t
\t\tif (textWidth != null)
\t\t{
\t\t\tdiv.style.width = textWidth + 'px';
\t\t\tdiv.style.whiteSpace = 'normal';
\t\t}
\t\telse
\t\t{
\t\t\tdiv.style.whiteSpace = 'nowrap';
\t\t}
\t\t
\t\t// Adds the text and inserts into DOM for updating of size
\t\tdiv.innerHTML = text;
\t\tdocument.body.appendChild(div);
\t\t
\t\t// Gets the size and removes from DOM
\t\tvar size = new mxRectangle(0, 0, div.offsetWidth, div.offsetHeight);
\t\tdocument.body.removeChild(div);
\t\t
\t\treturn size;
\t},
\t
\t/**
\t * Function: getViewXml
\t */
\tgetViewXml: function(graph, scale, cells, x0, y0)
\t{
\t\tx0 = (x0 != null) ? x0 : 0;
\t\ty0 = (y0 != null) ? y0 : 0;
\t\tscale = (scale != null) ? scale : 1;

\t\tif (cells == null)
\t\t{
\t\t\tvar model = graph.getModel();
\t\t\tcells = [model.getRoot()];
\t\t}
\t\t
\t\tvar view = graph.getView();
\t\tvar result = null;

\t\t// Disables events on the view
\t\tvar eventsEnabled = view.isEventsEnabled();
\t\tview.setEventsEnabled(false);

\t\t// Workaround for label bounds not taken into account for image export.
\t\t// Creates a temporary draw pane which is used for rendering the text.
\t\t// Text rendering is required for finding the bounds of the labels.
\t\tvar drawPane = view.drawPane;
\t\tvar overlayPane = view.overlayPane;

\t\tif (graph.dialect == mxConstants.DIALECT_SVG)
\t\t{
\t\t\tview.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\t\t\tview.canvas.appendChild(view.drawPane);

\t\t\t// Redirects cell overlays into temporary container
\t\t\tview.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\t\t\tview.canvas.appendChild(view.overlayPane);
\t\t}
\t\telse
\t\t{
\t\t\tview.drawPane = view.drawPane.cloneNode(false);
\t\t\tview.canvas.appendChild(view.drawPane);
\t\t\t
\t\t\t// Redirects cell overlays into temporary container
\t\t\tview.overlayPane = view.overlayPane.cloneNode(false);
\t\t\tview.canvas.appendChild(view.overlayPane);
\t\t}

\t\t// Resets the translation
\t\tvar translate = view.getTranslate();
\t\tview.translate = new mxPoint(x0, y0);

\t\t// Creates the temporary cell states in the view
\t\tvar temp = new mxTemporaryCellStates(graph.getView(), scale, cells);

\t\ttry
\t\t{
\t\t\tvar enc = new mxCodec();
\t\t\tresult = enc.encode(graph.getView());
\t\t}
\t\tfinally
\t\t{
\t\t\ttemp.destroy();
\t\t\tview.translate = translate;
\t\t\tview.canvas.removeChild(view.drawPane);
\t\t\tview.canvas.removeChild(view.overlayPane);
\t\t\tview.drawPane = drawPane;
\t\t\tview.overlayPane = overlayPane;
\t\t\tview.setEventsEnabled(eventsEnabled);
\t\t}

\t\treturn result;
\t},
\t
\t/**
\t * Function: getScaleForPageCount
\t * 
\t * Returns the scale to be used for printing the graph with the given
\t * bounds across the specifies number of pages with the given format. The
\t * scale is always computed such that it given the given amount or fewer
\t * pages in the print output. See <mxPrintPreview> for an example.
\t * 
\t * Parameters:
\t * 
\t * pageCount - Specifies the number of pages in the print output.
\t * graph - <mxGraph> that should be printed.
\t * pageFormat - Optional <mxRectangle> that specifies the page format.
\t * Default is <mxConstants.PAGE_FORMAT_A4_PORTRAIT>.
\t * border - The border along each side of every page.
\t */
\tgetScaleForPageCount: function(pageCount, graph, pageFormat, border)
\t{
\t\tif (pageCount < 1)
\t\t{
\t\t\t// We can't work with less than 1 page, return no scale
\t\t\t// change
\t\t\treturn 1;
\t\t}
\t\t
\t\tpageFormat = (pageFormat != null) ? pageFormat : mxConstants.PAGE_FORMAT_A4_PORTRAIT;
\t\tborder = (border != null) ? border : 0;
\t\t
\t\tvar availablePageWidth = pageFormat.width - (border * 2);
\t\tvar availablePageHeight = pageFormat.height - (border * 2);

\t\t// Work out the number of pages required if the
\t\t// graph is not scaled.
\t\tvar graphBounds = graph.getGraphBounds().clone();
\t\tvar sc = graph.getView().getScale();
\t\tgraphBounds.width /= sc;
\t\tgraphBounds.height /= sc;
\t\tvar graphWidth = graphBounds.width;
\t\tvar graphHeight = graphBounds.height;

\t\tvar scale = 1;
\t\t
\t\t// The ratio of the width/height for each printer page
\t\tvar pageFormatAspectRatio = availablePageWidth / availablePageHeight;
\t\t// The ratio of the width/height for the graph to be printer
\t\tvar graphAspectRatio = graphWidth / graphHeight;
\t\t
\t\t// The ratio of horizontal pages / vertical pages for this 
\t\t// graph to maintain its aspect ratio on this page format
\t\tvar pagesAspectRatio = graphAspectRatio / pageFormatAspectRatio;
\t\t
\t\t// Factor the square root of the page count up and down 
\t\t// by the pages aspect ratio to obtain a horizontal and 
\t\t// vertical page count that adds up to the page count
\t\t// and has the correct aspect ratio
\t\tvar pageRoot = Math.sqrt(pageCount);
\t\tvar pagesAspectRatioSqrt = Math.sqrt(pagesAspectRatio);
\t\tvar numRowPages = pageRoot * pagesAspectRatioSqrt;
\t\tvar numColumnPages = pageRoot / pagesAspectRatioSqrt;

\t\t// These value are rarely more than 2 rounding downs away from
\t\t// a total that meets the page count. In cases of one being less 
\t\t// than 1 page, the other value can be too high and take more iterations 
\t\t// In this case, just change that value to be the page count, since 
\t\t// we know the other value is 1
\t\tif (numRowPages < 1 && numColumnPages > pageCount)
\t\t{
\t\t\tvar scaleChange = numColumnPages / pageCount;
\t\t\tnumColumnPages = pageCount;
\t\t\tnumRowPages /= scaleChange;
\t\t}
\t\t
\t\tif (numColumnPages < 1 && numRowPages > pageCount)
\t\t{
\t\t\tvar scaleChange = numRowPages / pageCount;
\t\t\tnumRowPages = pageCount;
\t\t\tnumColumnPages /= scaleChange;
\t\t}\t\t

\t\tvar currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);

\t\tvar numLoops = 0;
\t\t
\t\t// Iterate through while the rounded up number of pages comes to
\t\t// a total greater than the required number
\t\twhile (currentTotalPages > pageCount)
\t\t{
\t\t\t// Round down the page count (rows or columns) that is
\t\t\t// closest to its next integer down in percentage terms.
\t\t\t// i.e. Reduce the page total by reducing the total
\t\t\t// page area by the least possible amount

\t\t\tvar roundRowDownProportion = Math.floor(numRowPages) / numRowPages;
\t\t\tvar roundColumnDownProportion = Math.floor(numColumnPages) / numColumnPages;
\t\t\t
\t\t\t// If the round down proportion is, work out the proportion to
\t\t\t// round down to 1 page less
\t\t\tif (roundRowDownProportion == 1)
\t\t\t{
\t\t\t\troundRowDownProportion = Math.floor(numRowPages-1) / numRowPages;
\t\t\t}
\t\t\tif (roundColumnDownProportion == 1)
\t\t\t{
\t\t\t\troundColumnDownProportion = Math.floor(numColumnPages-1) / numColumnPages;
\t\t\t}
\t\t\t
\t\t\t// Check which rounding down is smaller, but in the case of very small roundings
\t\t\t// try the other dimension instead
\t\t\tvar scaleChange = 1;
\t\t\t
\t\t\t// Use the higher of the two values
\t\t\tif (roundRowDownProportion > roundColumnDownProportion)
\t\t\t{
\t\t\t\tscaleChange = roundRowDownProportion;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tscaleChange = roundColumnDownProportion;
\t\t\t}

\t\t\tnumRowPages = numRowPages * scaleChange;
\t\t\tnumColumnPages = numColumnPages * scaleChange;
\t\t\tcurrentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);
\t\t\t
\t\t\tnumLoops++;
\t\t\t
\t\t\tif (numLoops > 10)
\t\t\t{
\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\t// Work out the scale from the number of row pages required
\t\t// The column pages will give the same value
\t\tvar posterWidth = availablePageWidth * numRowPages;
\t\tscale = posterWidth / graphWidth;
\t\t
\t\t// Allow for rounding errors
\t\treturn scale * 0.99999;
\t},
\t
\t/**
\t * Function: show
\t * 
\t * Copies the styles and the markup from the graph's container into the
\t * given document and removes all cursor styles. The document is returned.
\t * 
\t * This function should be called from within the document with the graph.
\t * If you experience problems with missing stylesheets in IE then try adding
\t * the domain to the trusted sites.
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> to be copied.
\t * doc - Document where the new graph is created.
\t * x0 - X-coordinate of the graph view origin. Default is 0.
\t * y0 - Y-coordinate of the graph view origin. Default is 0.
\t * w - Optional width of the graph view.
\t * h - Optional height of the graph view.
\t */
\tshow: function(graph, doc, x0, y0, w, h)
\t{
\t\tx0 = (x0 != null) ? x0 : 0;
\t\ty0 = (y0 != null) ? y0 : 0;
\t\t
\t\tif (doc == null)
\t\t{
\t\t\tvar wnd = window.open();
\t\t\tdoc = wnd.document;
\t\t}
\t\telse
\t\t{
\t\t\tdoc.open();
\t\t}

\t\t// Workaround for missing print output in IE9 standards
\t\tif (document.documentMode == 9)
\t\t{
\t\t\tdoc.writeln('<!--[if IE]><meta http-equiv=\"X-UA-Compatible\" content=\"IE=9\"><![endif]-->');
\t\t}
\t\t
\t\tvar bounds = graph.getGraphBounds();
\t\tvar dx = Math.ceil(x0 - bounds.x);
\t\tvar dy = Math.ceil(y0 - bounds.y);
\t\t
\t\tif (w == null)
\t\t{
\t\t\tw = Math.ceil(bounds.width + x0) + Math.ceil(Math.ceil(bounds.x) - bounds.x);
\t\t}
\t\t
\t\tif (h == null)
\t\t{
\t\t\th = Math.ceil(bounds.height + y0) + Math.ceil(Math.ceil(bounds.y) - bounds.y);
\t\t}
\t\t
\t\t// Needs a special way of creating the page so that no click is required
\t\t// to refresh the contents after the external CSS styles have been loaded.
\t\t// To avoid a click or programmatic refresh, the styleSheets[].cssText
\t\t// property is copied over from the original document.
\t\tif (mxClient.IS_IE || document.documentMode == 11)
\t\t{
\t\t\tvar html = '<html><head>';

\t\t\tvar base = document.getElementsByTagName('base');
\t\t\t
\t\t\tfor (var i = 0; i < base.length; i++)
\t\t\t{
\t\t\t\thtml += base[i].outerHTML;
\t\t\t}

\t\t\thtml += '<style>';

\t\t\t// Copies the stylesheets without having to load them again
\t\t\tfor (var i = 0; i < document.styleSheets.length; i++)
\t\t\t{
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\thtml += document.styleSheets[i].cssText;
\t\t\t\t}
\t\t\t\tcatch (e)
\t\t\t\t{
\t\t\t\t\t// ignore security exception
\t\t\t\t}
\t\t\t}

\t\t\thtml += '</style></head><body style=\"margin:0px;\">';
\t\t\t
\t\t\t// Copies the contents of the graph container
\t\t\thtml += '<div style=\"position:absolute;overflow:hidden;width:' + w + 'px;height:' + h + 'px;\"><div style=\"position:relative;left:' + dx + 'px;top:' + dy + 'px;\">';
\t\t\thtml += graph.container.innerHTML;
\t\t\thtml += '</div></div></body><html>';

\t\t\tdoc.writeln(html);
\t\t\tdoc.close();
\t\t}
\t\telse
\t\t{
\t\t\tdoc.writeln('<html><head>');
\t\t\t
\t\t\tvar base = document.getElementsByTagName('base');
\t\t\t
\t\t\tfor (var i = 0; i < base.length; i++)
\t\t\t{
\t\t\t\tdoc.writeln(mxUtils.getOuterHtml(base[i]));
\t\t\t}
\t\t\t
\t\t\tvar links = document.getElementsByTagName('link');
\t\t\t
\t\t\tfor (var i = 0; i < links.length; i++)
\t\t\t{
\t\t\t\tdoc.writeln(mxUtils.getOuterHtml(links[i]));
\t\t\t}
\t
\t\t\tvar styles = document.getElementsByTagName('style');
\t\t\t
\t\t\tfor (var i = 0; i < styles.length; i++)
\t\t\t{
\t\t\t\tdoc.writeln(mxUtils.getOuterHtml(styles[i]));
\t\t\t}

\t\t\tdoc.writeln('</head><body style=\"margin:0px;\"></body></html>');
\t\t\tdoc.close();

\t\t\tvar outer = doc.createElement('div');
\t\t\touter.position = 'absolute';
\t\t\touter.overflow = 'hidden';
\t\t\touter.style.width = w + 'px';
\t\t\touter.style.height = h + 'px';

\t\t\t// Required for HTML labels if foreignObjects are disabled
\t\t\tvar div = doc.createElement('div');
\t\t\tdiv.style.position = 'absolute';
\t\t\tdiv.style.left = dx + 'px';
\t\t\tdiv.style.top = dy + 'px';

\t\t\tvar node = graph.container.firstChild;
\t\t\tvar svg = null;
\t\t\t
\t\t\twhile (node != null)
\t\t\t{
\t\t\t\tvar clone = node.cloneNode(true);
\t\t\t\t
\t\t\t\tif (node == graph.view.drawPane.ownerSVGElement)
\t\t\t\t{
\t\t\t\t\touter.appendChild(clone);
\t\t\t\t\tsvg = clone;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tdiv.appendChild(clone);
\t\t\t\t}
\t\t\t\t
\t\t\t\tnode = node.nextSibling;
\t\t\t}

\t\t\tdoc.body.appendChild(outer);
\t\t\t
\t\t\tif (div.firstChild != null)
\t\t\t{
\t\t\t\tdoc.body.appendChild(div);
\t\t\t}
\t\t\t\t\t\t
\t\t\tif (svg != null)
\t\t\t{
\t\t\t\tsvg.style.minWidth = '';
\t\t\t\tsvg.style.minHeight = '';
\t\t\t\tsvg.firstChild.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
\t\t\t}
\t\t}
\t\t
\t\tmxUtils.removeCursors(doc.body);
\t
\t\treturn doc;
\t},
\t
\t/**
\t * Function: printScreen
\t * 
\t * Prints the specified graph using a new window and the built-in print
\t * dialog.
\t * 
\t * This function should be called from within the document with the graph.
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> to be printed.
\t */
\tprintScreen: function(graph)
\t{
\t\tvar wnd = window.open();
\t\tvar bounds = graph.getGraphBounds();
\t\tmxUtils.show(graph, wnd.document);
\t\t
\t\tvar print = function()
\t\t{
\t\t\twnd.focus();
\t\t\twnd.print();
\t\t\twnd.close();
\t\t};
\t\t
\t\t// Workaround for Google Chrome which needs a bit of a
\t\t// delay in order to render the SVG contents
\t\tif (mxClient.IS_GC)
\t\t{
\t\t\twnd.setTimeout(print, 500);
\t\t}
\t\telse
\t\t{
\t\t\tprint();
\t\t}
\t},
\t
\t/**
\t * Function: popup
\t * 
\t * Shows the specified text content in a new <mxWindow> or a new browser
\t * window if isInternalWindow is false.
\t * 
\t * Parameters:
\t * 
\t * content - String that specifies the text to be displayed.
\t * isInternalWindow - Optional boolean indicating if an mxWindow should be
\t * used instead of a new browser window. Default is false.
\t */
\tpopup: function(content, isInternalWindow)
\t{
\t   \tif (isInternalWindow)
\t   \t{
\t\t\tvar div = document.createElement('div');
\t\t\t
\t\t\tdiv.style.overflow = 'scroll';
\t\t\tdiv.style.width = '636px';
\t\t\tdiv.style.height = '460px';
\t\t\t
\t\t\tvar pre = document.createElement('pre');
\t\t    pre.innerHTML = mxUtils.htmlEntities(content, false).
\t\t    \treplace(/\\n/g,'<br>').replace(/ /g, '&nbsp;');
\t\t\t
\t\t\tdiv.appendChild(pre);
\t\t\t
\t\t\tvar w = document.body.clientWidth;
\t\t\tvar h = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight)
\t\t\tvar wnd = new mxWindow('Popup Window', div,
\t\t\t\tw/2-320, h/2-240, 640, 480, false, true);

\t\t\twnd.setClosable(true);
\t\t\twnd.setVisible(true);
\t\t}
\t\telse
\t\t{
\t\t\t// Wraps up the XML content in a textarea
\t\t\tif (mxClient.IS_NS)
\t\t\t{
\t\t\t    var wnd = window.open();
\t\t\t\twnd.document.writeln('<pre>'+mxUtils.htmlEntities(content)+'</pre');
\t\t\t   \twnd.document.close();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t    var wnd = window.open();
\t\t\t    var pre = wnd.document.createElement('pre');
\t\t\t    pre.innerHTML = mxUtils.htmlEntities(content, false).
\t\t\t    \treplace(/\\n/g,'<br>').replace(/ /g, '&nbsp;');
\t\t\t   \twnd.document.body.appendChild(pre);
\t\t\t}
\t   \t}
\t},
\t
\t/**
\t * Function: alert
\t * 
\t * Displayss the given alert in a new dialog. This implementation uses the
\t * built-in alert function. This is used to display validation errors when
\t * connections cannot be changed or created.
\t * 
\t * Parameters:
\t * 
\t * message - String specifying the message to be displayed.
\t */
\talert: function(message)
\t{
\t\talert(message);
\t},
\t
\t/**
\t * Function: prompt
\t * 
\t * Displays the given message in a prompt dialog. This implementation uses
\t * the built-in prompt function.
\t * 
\t * Parameters:
\t * 
\t * message - String specifying the message to be displayed.
\t * defaultValue - Optional string specifying the default value.
\t */
\tprompt: function(message, defaultValue)
\t{
\t\treturn prompt(message, (defaultValue != null) ? defaultValue : '');
\t},
\t
\t/**
\t * Function: confirm
\t * 
\t * Displays the given message in a confirm dialog. This implementation uses
\t * the built-in confirm function.
\t * 
\t * Parameters:
\t * 
\t * message - String specifying the message to be displayed.
\t */
\tconfirm: function(message)
\t{
\t\treturn confirm(message);
\t},

\t/**
\t * Function: error
\t * 
\t * Displays the given error message in a new <mxWindow> of the given width.
\t * If close is true then an additional close button is added to the window.
\t * The optional icon specifies the icon to be used for the window. Default
\t * is <mxUtils.errorImage>.
\t * 
\t * Parameters:
\t * 
\t * message - String specifying the message to be displayed.
\t * width - Integer specifying the width of the window.
\t * close - Optional boolean indicating whether to add a close button.
\t * icon - Optional icon for the window decoration.
\t */
\terror: function(message, width, close, icon)
\t{
\t\tvar div = document.createElement('div');
\t\tdiv.style.padding = '20px';

\t\tvar img = document.createElement('img');
\t\timg.setAttribute('src', icon || mxUtils.errorImage);
\t\timg.setAttribute('valign', 'bottom');
\t\timg.style.verticalAlign = 'middle';
\t\tdiv.appendChild(img);

\t\tdiv.appendChild(document.createTextNode('\\u00a0')); // &nbsp;
\t\tdiv.appendChild(document.createTextNode('\\u00a0')); // &nbsp;
\t\tdiv.appendChild(document.createTextNode('\\u00a0')); // &nbsp;
\t\tmxUtils.write(div, message);

\t\tvar w = document.body.clientWidth;
\t\tvar h = (document.body.clientHeight || document.documentElement.clientHeight);
\t\tvar warn = new mxWindow(mxResources.get(mxUtils.errorResource) ||
\t\t\tmxUtils.errorResource, div, (w-width)/2, h/4, width, null,
\t\t\tfalse, true);

\t\tif (close)
\t\t{
\t\t\tmxUtils.br(div);
\t\t\t
\t\t\tvar tmp = document.createElement('p');
\t\t\tvar button = document.createElement('button');

\t\t\tif (mxClient.IS_IE)
\t\t\t{
\t\t\t\tbutton.style.cssText = 'float:right';
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tbutton.setAttribute('style', 'float:right');
\t\t\t}

\t\t\tmxEvent.addListener(button, 'click', function(evt)
\t\t\t{
\t\t\t\twarn.destroy();
\t\t\t});

\t\t\tmxUtils.write(button, mxResources.get(mxUtils.closeResource) ||
\t\t\t\tmxUtils.closeResource);
\t\t\t
\t\t\ttmp.appendChild(button);
\t\t\tdiv.appendChild(tmp);
\t\t\t
\t\t\tmxUtils.br(div);
\t\t\t
\t\t\twarn.setClosable(true);
\t\t}
\t\t
\t\twarn.setVisible(true);
\t\t
\t\treturn warn;
\t},

\t/**
\t * Function: makeDraggable
\t * 
\t * Configures the given DOM element to act as a drag source for the
\t * specified graph. Returns a a new <mxDragSource>. If
\t * <mxDragSource.guideEnabled> is enabled then the x and y arguments must
\t * be used in funct to match the preview location.
\t * 
\t * Example:
\t * 
\t * (code)
\t * var funct = function(graph, evt, cell, x, y)
\t * {
\t *   if (graph.canImportCell(cell))
\t *   {
\t *     var parent = graph.getDefaultParent();
\t *     var vertex = null;
\t *     
\t *     graph.getModel().beginUpdate();
\t *     try
\t *     {
\t * \t     vertex = graph.insertVertex(parent, null, 'Hello', x, y, 80, 30);
\t *     }
\t *     finally
\t *     {
\t *       graph.getModel().endUpdate();
\t *     }
\t *
\t *     graph.setSelectionCell(vertex);
\t *   }
\t * }
\t * 
\t * var img = document.createElement('img');
\t * img.setAttribute('src', 'editors/images/rectangle.gif');
\t * img.style.position = 'absolute';
\t * img.style.left = '0px';
\t * img.style.top = '0px';
\t * img.style.width = '16px';
\t * img.style.height = '16px';
\t * 
\t * var dragImage = img.cloneNode(true);
\t * dragImage.style.width = '32px';
\t * dragImage.style.height = '32px';
\t * mxUtils.makeDraggable(img, graph, funct, dragImage);
\t * document.body.appendChild(img);
\t * (end)
\t * 
\t * Parameters:
\t * 
\t * element - DOM element to make draggable.
\t * graphF - <mxGraph> that acts as the drop target or a function that takes a
\t * mouse event and returns the current <mxGraph>.
\t * funct - Function to execute on a successful drop.
\t * dragElement - Optional DOM node to be used for the drag preview.
\t * dx - Optional horizontal offset between the cursor and the drag
\t * preview.
\t * dy - Optional vertical offset between the cursor and the drag
\t * preview.
\t * autoscroll - Optional boolean that specifies if autoscroll should be
\t * used. Default is mxGraph.autoscroll.
\t * scalePreview - Optional boolean that specifies if the preview element
\t * should be scaled according to the graph scale. If this is true, then
\t * the offsets will also be scaled. Default is false.
\t * highlightDropTargets - Optional boolean that specifies if dropTargets
\t * should be highlighted. Default is true.
\t * getDropTarget - Optional function to return the drop target for a given
\t * location (x, y). Default is mxGraph.getCellAt.
\t */
\tmakeDraggable: function(element, graphF, funct, dragElement, dx, dy, autoscroll,
\t\t\tscalePreview, highlightDropTargets, getDropTarget)
\t{
\t\tvar dragSource = new mxDragSource(element, funct);
\t\tdragSource.dragOffset = new mxPoint((dx != null) ? dx : 0,
\t\t\t(dy != null) ? dy : mxConstants.TOOLTIP_VERTICAL_OFFSET);
\t\tdragSource.autoscroll = autoscroll;
\t\t
\t\t// Cannot enable this by default. This needs to be enabled in the caller
\t\t// if the funct argument uses the new x- and y-arguments.
\t\tdragSource.setGuidesEnabled(false);
\t\t
\t\tif (highlightDropTargets != null)
\t\t{
\t\t\tdragSource.highlightDropTargets = highlightDropTargets;
\t\t}
\t\t
\t\t// Overrides function to find drop target cell
\t\tif (getDropTarget != null)
\t\t{
\t\t\tdragSource.getDropTarget = getDropTarget;
\t\t}
\t\t
\t\t// Overrides function to get current graph
\t\tdragSource.getGraphForEvent = function(evt)
\t\t{
\t\t\treturn (typeof(graphF) == 'function') ? graphF(evt) : graphF;
\t\t};
\t\t
\t\t// Translates switches into dragSource customizations
\t\tif (dragElement != null)
\t\t{
\t\t\tdragSource.createDragElement = function()
\t\t\t{
\t\t\t\treturn dragElement.cloneNode(true);
\t\t\t};
\t\t\t
\t\t\tif (scalePreview)
\t\t\t{
\t\t\t\tdragSource.createPreviewElement = function(graph)
\t\t\t\t{
\t\t\t\t\tvar elt = dragElement.cloneNode(true);

\t\t\t\t\tvar w = parseInt(elt.style.width);
\t\t\t\t\tvar h = parseInt(elt.style.height);
\t\t\t\t\telt.style.width = Math.round(w * graph.view.scale) + 'px';
\t\t\t\t\telt.style.height = Math.round(h * graph.view.scale) + 'px';
\t\t\t\t\t
\t\t\t\t\treturn elt;
\t\t\t\t};
\t\t\t}
\t\t}
\t\t
\t\treturn dragSource;
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
 var mxConstants =
 {
\t/**
\t * Class: mxConstants
\t * 
\t * Defines various global constants.
\t * 
\t * Variable: DEFAULT_HOTSPOT
\t * 
\t * Defines the portion of the cell which is to be used as a connectable
\t * region. Default is 0.3. Possible values are 0 < x <= 1. 
\t */
\tDEFAULT_HOTSPOT: 0.3,

\t/**
\t * Variable: MIN_HOTSPOT_SIZE
\t * 
\t * Defines the minimum size in pixels of the portion of the cell which is
\t * to be used as a connectable region. Default is 8.
\t */
\tMIN_HOTSPOT_SIZE: 8,

\t/**
\t * Variable: MAX_HOTSPOT_SIZE
\t * 
\t * Defines the maximum size in pixels of the portion of the cell which is
\t * to be used as a connectable region. Use 0 for no maximum. Default is 0.
\t */
\tMAX_HOTSPOT_SIZE: 0,

\t/**
\t * Variable: RENDERING_HINT_EXACT
\t * 
\t * Defines the exact rendering hint.
\t */
\tRENDERING_HINT_EXACT: 'exact',

\t/**
\t * Variable: RENDERING_HINT_FASTER
\t * 
\t * Defines the faster rendering hint.
\t */
\tRENDERING_HINT_FASTER: 'faster',

\t/**
\t * Variable: RENDERING_HINT_FASTEST
\t * 
\t * Defines the fastest rendering hint.
\t */
\tRENDERING_HINT_FASTEST: 'fastest',

\t/**
\t * Variable: DIALECT_SVG
\t * 
\t * Defines the SVG display dialect name.
\t */
\tDIALECT_SVG: 'svg',

\t/**
\t * Variable: DIALECT_VML
\t * 
\t * Defines the VML display dialect name.
\t */
\tDIALECT_VML: 'vml',

\t/**
\t * Variable: DIALECT_MIXEDHTML
\t * 
\t * Defines the mixed HTML display dialect name.
\t */
\tDIALECT_MIXEDHTML: 'mixedHtml',

\t/**
\t * Variable: DIALECT_PREFERHTML
\t * 
\t * Defines the preferred HTML display dialect name.
\t */
\tDIALECT_PREFERHTML: 'preferHtml',

\t/**
\t * Variable: DIALECT_STRICTHTML
\t * 
\t * Defines the strict HTML display dialect.
\t */
\tDIALECT_STRICTHTML: 'strictHtml',

\t/**
\t * Variable: NS_SVG
\t * 
\t * Defines the SVG namespace.
\t */
\tNS_SVG: 'http://www.w3.org/2000/svg',

\t/**
\t * Variable: NS_XHTML
\t * 
\t * Defines the XHTML namespace.
\t */
\tNS_XHTML: 'http://www.w3.org/1999/xhtml',

\t/**
\t * Variable: NS_XLINK
\t * 
\t * Defines the XLink namespace.
\t */
\tNS_XLINK: 'http://www.w3.org/1999/xlink',

\t/**
\t * Variable: SHADOWCOLOR
\t * 
\t * Defines the color to be used to draw shadows in shapes and windows.
\t * Default is gray.
\t */
\tSHADOWCOLOR: 'gray',

\t/**
\t * Variable: VML_SHADOWCOLOR
\t * 
\t * Used for shadow color in filters where transparency is not supported
\t * (Microsoft Internet Explorer). Default is gray.
\t */
\tVML_SHADOWCOLOR: 'gray',

\t/**
\t * Variable: SHADOW_OFFSET_X
\t * 
\t * Specifies the x-offset of the shadow. Default is 2.
\t */
\tSHADOW_OFFSET_X: 2,

\t/**
\t * Variable: SHADOW_OFFSET_Y
\t * 
\t * Specifies the y-offset of the shadow. Default is 3.
\t */
\tSHADOW_OFFSET_Y: 3,
\t
\t/**
\t * Variable: SHADOW_OPACITY
\t * 
\t * Defines the opacity for shadows. Default is 1.
\t */
\tSHADOW_OPACITY: 1,
 
\t/**
\t * Variable: NODETYPE_ELEMENT
\t * 
\t * DOM node of type ELEMENT.
\t */
\tNODETYPE_ELEMENT: 1,

\t/**
\t * Variable: NODETYPE_ATTRIBUTE
\t * 
\t * DOM node of type ATTRIBUTE.
\t */
\tNODETYPE_ATTRIBUTE: 2,

\t/**
\t * Variable: NODETYPE_TEXT
\t * 
\t * DOM node of type TEXT.
\t */
\tNODETYPE_TEXT: 3,

\t/**
\t * Variable: NODETYPE_CDATA
\t * 
\t * DOM node of type CDATA.
\t */
\tNODETYPE_CDATA: 4,
\t
\t/**
\t * Variable: NODETYPE_ENTITY_REFERENCE
\t * 
\t * DOM node of type ENTITY_REFERENCE.
\t */
\tNODETYPE_ENTITY_REFERENCE: 5,

\t/**
\t * Variable: NODETYPE_ENTITY
\t * 
\t * DOM node of type ENTITY.
\t */
\tNODETYPE_ENTITY: 6,

\t/**
\t * Variable: NODETYPE_PROCESSING_INSTRUCTION
\t * 
\t * DOM node of type PROCESSING_INSTRUCTION.
\t */
\tNODETYPE_PROCESSING_INSTRUCTION: 7,

\t/**
\t * Variable: NODETYPE_COMMENT
\t * 
\t * DOM node of type COMMENT.
\t */
\tNODETYPE_COMMENT: 8,
\t\t
\t/**
\t * Variable: NODETYPE_DOCUMENT
\t * 
\t * DOM node of type DOCUMENT.
\t */
\tNODETYPE_DOCUMENT: 9,

\t/**
\t * Variable: NODETYPE_DOCUMENTTYPE
\t * 
\t * DOM node of type DOCUMENTTYPE.
\t */
\tNODETYPE_DOCUMENTTYPE: 10,

\t/**
\t * Variable: NODETYPE_DOCUMENT_FRAGMENT
\t * 
\t * DOM node of type DOCUMENT_FRAGMENT.
\t */
\tNODETYPE_DOCUMENT_FRAGMENT: 11,

\t/**
\t * Variable: NODETYPE_NOTATION
\t * 
\t * DOM node of type NOTATION.
\t */
\tNODETYPE_NOTATION: 12,
\t
\t/**
\t * Variable: TOOLTIP_VERTICAL_OFFSET
\t * 
\t * Defines the vertical offset for the tooltip.
\t * Default is 16.
\t */
\tTOOLTIP_VERTICAL_OFFSET: 16,

\t/**
\t * Variable: DEFAULT_VALID_COLOR
\t * 
\t * Specifies the default valid color. Default is #0000FF.
\t */
\tDEFAULT_VALID_COLOR: '#00FF00',

\t/**
\t * Variable: DEFAULT_INVALID_COLOR
\t * 
\t * Specifies the default invalid color. Default is #FF0000.
\t */
\tDEFAULT_INVALID_COLOR: '#FF0000',

\t/**
\t * Variable: OUTLINE_HIGHLIGHT_COLOR
\t * 
\t * Specifies the default highlight color for shape outlines.
\t * Default is #0000FF. This is used in <mxEdgeHandler>.
\t */
\tOUTLINE_HIGHLIGHT_COLOR: '#00FF00',

\t/**
\t * Variable: OUTLINE_HIGHLIGHT_COLOR
\t * 
\t * Defines the strokewidth to be used for shape outlines.
\t * Default is 5. This is used in <mxEdgeHandler>.
\t */
\tOUTLINE_HIGHLIGHT_STROKEWIDTH: 5,

\t/**
\t * Variable: HIGHLIGHT_STROKEWIDTH
\t * 
\t * Defines the strokewidth to be used for the highlights.
\t * Default is 3.
\t */
\tHIGHLIGHT_STROKEWIDTH: 3,

\t/**
\t * Variable: CONSTRAINT_HIGHLIGHT_SIZE
\t * 
\t * Size of the constraint highlight (in px). Default is 2.
\t */
\tHIGHLIGHT_SIZE: 2,
\t
\t/**
\t * Variable: HIGHLIGHT_OPACITY
\t * 
\t * Opacity (in %) used for the highlights (including outline).
\t * Default is 100.
\t */
\tHIGHLIGHT_OPACITY: 100,
\t
\t/**
\t * Variable: CURSOR_MOVABLE_VERTEX
\t * 
\t * Defines the cursor for a movable vertex. Default is 'move'.
\t */
\tCURSOR_MOVABLE_VERTEX: 'move',
\t
\t/**
\t * Variable: CURSOR_MOVABLE_EDGE
\t * 
\t * Defines the cursor for a movable edge. Default is 'move'.
\t */
\tCURSOR_MOVABLE_EDGE: 'move',
\t
\t/**
\t * Variable: CURSOR_LABEL_HANDLE
\t * 
\t * Defines the cursor for a movable label. Default is 'default'.
\t */
\tCURSOR_LABEL_HANDLE: 'default',
\t
\t/**
\t * Variable: CURSOR_TERMINAL_HANDLE
\t * 
\t * Defines the cursor for a terminal handle. Default is 'pointer'.
\t */
\tCURSOR_TERMINAL_HANDLE: 'pointer',
\t
\t/**
\t * Variable: CURSOR_BEND_HANDLE
\t * 
\t * Defines the cursor for a movable bend. Default is 'crosshair'.
\t */
\tCURSOR_BEND_HANDLE: 'crosshair',

\t/**
\t * Variable: CURSOR_VIRTUAL_BEND_HANDLE
\t * 
\t * Defines the cursor for a movable bend. Default is 'crosshair'.
\t */
\tCURSOR_VIRTUAL_BEND_HANDLE: 'crosshair',
\t
\t/**
\t * Variable: CURSOR_CONNECT
\t * 
\t * Defines the cursor for a connectable state. Default is 'pointer'.
\t */
\tCURSOR_CONNECT: 'pointer',

\t/**
\t * Variable: HIGHLIGHT_COLOR
\t * 
\t * Defines the color to be used for the cell highlighting.
\t * Use 'none' for no color. Default is #00FF00.
\t */
\tHIGHLIGHT_COLOR: '#00FF00',

\t/**
\t * Variable: TARGET_HIGHLIGHT_COLOR
\t * 
\t * Defines the color to be used for highlighting a target cell for a new
\t * or changed connection. Note that this may be either a source or
\t * target terminal in the graph. Use 'none' for no color.
\t * Default is #0000FF.
\t */
\tCONNECT_TARGET_COLOR: '#0000FF',

\t/**
\t * Variable: INVALID_CONNECT_TARGET_COLOR
\t * 
\t * Defines the color to be used for highlighting a invalid target cells
\t * for a new or changed connections. Note that this may be either a source
\t * or target terminal in the graph. Use 'none' for no color. Default is
\t * #FF0000.
\t */
\tINVALID_CONNECT_TARGET_COLOR: '#FF0000',

\t/**
\t * Variable: DROP_TARGET_COLOR
\t * 
\t * Defines the color to be used for the highlighting target parent cells
\t * (for drag and drop). Use 'none' for no color. Default is #0000FF.
\t */
\tDROP_TARGET_COLOR: '#0000FF',

\t/**
\t * Variable: VALID_COLOR
\t * 
\t * Defines the color to be used for the coloring valid connection
\t * previews. Use 'none' for no color. Default is #FF0000.
\t */
\tVALID_COLOR: '#00FF00',

\t/**
\t * Variable: INVALID_COLOR
\t * 
\t * Defines the color to be used for the coloring invalid connection
\t * previews. Use 'none' for no color. Default is #FF0000.
\t */
\tINVALID_COLOR: '#FF0000',

\t/**
\t * Variable: EDGE_SELECTION_COLOR
\t * 
\t * Defines the color to be used for the selection border of edges. Use
\t * 'none' for no color. Default is #00FF00.
\t */
\tEDGE_SELECTION_COLOR: '#00FF00',

\t/**
\t * Variable: VERTEX_SELECTION_COLOR
\t * 
\t * Defines the color to be used for the selection border of vertices. Use
\t * 'none' for no color. Default is #00FF00.
\t */
\tVERTEX_SELECTION_COLOR: '#00FF00',

\t/**
\t * Variable: VERTEX_SELECTION_STROKEWIDTH
\t * 
\t * Defines the strokewidth to be used for vertex selections.
\t * Default is 1.
\t */
\tVERTEX_SELECTION_STROKEWIDTH: 1,

\t/**
\t * Variable: EDGE_SELECTION_STROKEWIDTH
\t * 
\t * Defines the strokewidth to be used for edge selections.
\t * Default is 1.
\t */
\tEDGE_SELECTION_STROKEWIDTH: 1,

\t/**
\t * Variable: SELECTION_DASHED
\t * 
\t * Defines the dashed state to be used for the vertex selection
\t * border. Default is true.
\t */
\tVERTEX_SELECTION_DASHED: true,

\t/**
\t * Variable: SELECTION_DASHED
\t * 
\t * Defines the dashed state to be used for the edge selection
\t * border. Default is true.
\t */
\tEDGE_SELECTION_DASHED: true,

\t/**
\t * Variable: GUIDE_COLOR
\t * 
\t * Defines the color to be used for the guidelines in mxGraphHandler.
\t * Default is #FF0000.
\t */
\tGUIDE_COLOR: '#FF0000',

\t/**
\t * Variable: GUIDE_STROKEWIDTH
\t * 
\t * Defines the strokewidth to be used for the guidelines in mxGraphHandler.
\t * Default is 1.
\t */
\tGUIDE_STROKEWIDTH: 1,

\t/**
\t * Variable: OUTLINE_COLOR
\t * 
\t * Defines the color to be used for the outline rectangle
\t * border.  Use 'none' for no color. Default is #0099FF.
\t */
\tOUTLINE_COLOR: '#0099FF',

\t/**
\t * Variable: OUTLINE_STROKEWIDTH
\t * 
\t * Defines the strokewidth to be used for the outline rectangle
\t * stroke width. Default is 3.
\t */
\tOUTLINE_STROKEWIDTH: (mxClient.IS_IE) ? 2 : 3,

\t/**
\t * Variable: HANDLE_SIZE
\t * 
\t * Defines the default size for handles. Default is 6.
\t */
\tHANDLE_SIZE: 6,

\t/**
\t * Variable: LABEL_HANDLE_SIZE
\t * 
\t * Defines the default size for label handles. Default is 4.
\t */
\tLABEL_HANDLE_SIZE: 4,

\t/**
\t * Variable: HANDLE_FILLCOLOR
\t * 
\t * Defines the color to be used for the handle fill color. Use 'none' for
\t * no color. Default is #00FF00 (green).
\t */
\tHANDLE_FILLCOLOR: '#00FF00',

\t/**
\t * Variable: HANDLE_STROKECOLOR
\t * 
\t * Defines the color to be used for the handle stroke color. Use 'none' for
\t * no color. Default is black.
\t */
\tHANDLE_STROKECOLOR: 'black',

\t/**
\t * Variable: LABEL_HANDLE_FILLCOLOR
\t * 
\t * Defines the color to be used for the label handle fill color. Use 'none'
\t * for no color. Default is yellow.
\t */
\tLABEL_HANDLE_FILLCOLOR: 'yellow',

\t/**
\t * Variable: CONNECT_HANDLE_FILLCOLOR
\t * 
\t * Defines the color to be used for the connect handle fill color. Use
\t * 'none' for no color. Default is #0000FF (blue).
\t */
\tCONNECT_HANDLE_FILLCOLOR: '#0000FF',

\t/**
\t * Variable: LOCKED_HANDLE_FILLCOLOR
\t * 
\t * Defines the color to be used for the locked handle fill color. Use
\t * 'none' for no color. Default is #FF0000 (red).
\t */
\tLOCKED_HANDLE_FILLCOLOR: '#FF0000',

\t/**
\t * Variable: OUTLINE_HANDLE_FILLCOLOR
\t * 
\t * Defines the color to be used for the outline sizer fill color. Use
\t * 'none' for no color. Default is #00FFFF.
\t */
\tOUTLINE_HANDLE_FILLCOLOR: '#00FFFF',

\t/**
\t * Variable: OUTLINE_HANDLE_STROKECOLOR
\t * 
\t * Defines the color to be used for the outline sizer stroke color. Use
\t * 'none' for no color. Default is #0033FF.
\t */
\tOUTLINE_HANDLE_STROKECOLOR: '#0033FF',

\t/**
\t * Variable: DEFAULT_FONTFAMILY
\t * 
\t * Defines the default family for all fonts. Default is Arial,Helvetica.
\t */
\tDEFAULT_FONTFAMILY: 'Arial,Helvetica',

\t/**
\t * Variable: DEFAULT_FONTSIZE
\t * 
\t * Defines the default size (in px). Default is 11.
\t */
\tDEFAULT_FONTSIZE: 11,

\t/**
\t * Variable: DEFAULT_TEXT_DIRECTION
\t * 
\t * Defines the default value for the <STYLE_TEXT_DIRECTION> if no value is
\t * defined for it in the style. Default value is an empty string which means
\t * the default system setting is used and no direction is set.
\t */
\tDEFAULT_TEXT_DIRECTION: '',

\t/**
\t * Variable: LINE_HEIGHT
\t * 
\t * Defines the default line height for text labels. Default is 1.2.
\t */
\tLINE_HEIGHT: 1.2,

\t/**
\t * Variable: WORD_WRAP
\t * 
\t * Defines the CSS value for the word-wrap property. Default is \"normal\".
\t * Change this to \"break-word\" to allow long words to be able to be broken
\t * and wrap onto the next line.
\t */
\tWORD_WRAP: 'normal',

\t/**
\t * Variable: ABSOLUTE_LINE_HEIGHT
\t * 
\t * Specifies if absolute line heights should be used (px) in CSS. Default
\t * is false. Set this to true for backwards compatibility.
\t */
\tABSOLUTE_LINE_HEIGHT: false,

\t/**
\t * Variable: DEFAULT_FONTSTYLE
\t * 
\t * Defines the default style for all fonts. Default is 0. This can be set
\t * to any combination of font styles as follows.
\t * 
\t * (code)
\t * mxConstants.DEFAULT_FONTSTYLE = mxConstants.FONT_BOLD | mxConstants.FONT_ITALIC;
\t * (end)
\t */
\tDEFAULT_FONTSTYLE: 0,

\t/**
\t * Variable: DEFAULT_STARTSIZE
\t * 
\t * Defines the default start size for swimlanes. Default is 40.
\t */
\tDEFAULT_STARTSIZE: 40,

\t/**
\t * Variable: DEFAULT_MARKERSIZE
\t * 
\t * Defines the default size for all markers. Default is 6.
\t */
\tDEFAULT_MARKERSIZE: 6,

\t/**
\t * Variable: DEFAULT_IMAGESIZE
\t * 
\t * Defines the default width and height for images used in the
\t * label shape. Default is 24.
\t */
\tDEFAULT_IMAGESIZE: 24,

\t/**
\t * Variable: ENTITY_SEGMENT
\t * 
\t * Defines the length of the horizontal segment of an Entity Relation.
\t * This can be overridden using <mxConstants.STYLE_SEGMENT> style.
\t * Default is 30.
\t */
\tENTITY_SEGMENT: 30,

\t/**
\t * Variable: RECTANGLE_ROUNDING_FACTOR
\t * 
\t * Defines the rounding factor for rounded rectangles in percent between
\t * 0 and 1. Values should be smaller than 0.5. Default is 0.15.
\t */
\tRECTANGLE_ROUNDING_FACTOR: 0.15,

\t/**
\t * Variable: LINE_ARCSIZE
\t * 
\t * Defines the size of the arcs for rounded edges. Default is 20.
\t */
\tLINE_ARCSIZE: 20,

\t/**
\t * Variable: ARROW_SPACING
\t * 
\t * Defines the spacing between the arrow shape and its terminals. Default is 0.
\t */
\tARROW_SPACING: 0,

\t/**
\t * Variable: ARROW_WIDTH
\t * 
\t * Defines the width of the arrow shape. Default is 30.
\t */
\tARROW_WIDTH: 30,

\t/**
\t * Variable: ARROW_SIZE
\t * 
\t * Defines the size of the arrowhead in the arrow shape. Default is 30.
\t */
\tARROW_SIZE: 30,

\t/**
\t * Variable: PAGE_FORMAT_A4_PORTRAIT
\t * 
\t * Defines the rectangle for the A4 portrait page format. The dimensions
\t * of this page format are 826x1169 pixels.
\t */
\tPAGE_FORMAT_A4_PORTRAIT: new mxRectangle(0, 0, 827, 1169),

\t/**
\t * Variable: PAGE_FORMAT_A4_PORTRAIT
\t * 
\t * Defines the rectangle for the A4 portrait page format. The dimensions
\t * of this page format are 826x1169 pixels.
\t */
\tPAGE_FORMAT_A4_LANDSCAPE: new mxRectangle(0, 0, 1169, 827),

\t/**
\t * Variable: PAGE_FORMAT_LETTER_PORTRAIT
\t * 
\t * Defines the rectangle for the Letter portrait page format. The
\t * dimensions of this page format are 850x1100 pixels.
\t */
\tPAGE_FORMAT_LETTER_PORTRAIT: new mxRectangle(0, 0, 850, 1100),

\t/**
\t * Variable: PAGE_FORMAT_LETTER_PORTRAIT
\t * 
\t * Defines the rectangle for the Letter portrait page format. The dimensions
\t * of this page format are 850x1100 pixels.
\t */
\tPAGE_FORMAT_LETTER_LANDSCAPE: new mxRectangle(0, 0, 1100, 850),

\t/**
\t * Variable: NONE
\t * 
\t * Defines the value for none. Default is \"none\".
\t */
\tNONE: 'none',

\t/**
\t * Variable: STYLE_PERIMETER
\t * 
\t * Defines the key for the perimeter style. This is a function that defines
\t * the perimeter around a particular shape. Possible values are the
\t * functions defined in <mxPerimeter>. Alternatively, the constants in this
\t * class that start with \"PERIMETER_\" may be used to access
\t * perimeter styles in <mxStyleRegistry>. Value is \"perimeter\".
\t */
\tSTYLE_PERIMETER: 'perimeter',
\t
\t/**
\t * Variable: STYLE_SOURCE_PORT
\t * 
\t * Defines the ID of the cell that should be used for computing the
\t * perimeter point of the source for an edge. This allows for graphically
\t * connecting to a cell while keeping the actual terminal of the edge.
\t * Value is \"sourcePort\".
\t */
\tSTYLE_SOURCE_PORT: 'sourcePort',
\t
\t/**
\t * Variable: STYLE_TARGET_PORT
\t * 
\t * Defines the ID of the cell that should be used for computing the
\t * perimeter point of the target for an edge. This allows for graphically
\t * connecting to a cell while keeping the actual terminal of the edge.
\t * Value is \"targetPort\".
\t */
\tSTYLE_TARGET_PORT: 'targetPort',

\t/**
\t * Variable: STYLE_PORT_CONSTRAINT
\t * 
\t * Defines the direction(s) that edges are allowed to connect to cells in.
\t * Possible values are \"DIRECTION_NORTH, DIRECTION_SOUTH, 
\t * DIRECTION_EAST\" and \"DIRECTION_WEST\". Value is
\t * \"portConstraint\".
\t */
\tSTYLE_PORT_CONSTRAINT: 'portConstraint',

\t/**
\t * Variable: STYLE_PORT_CONSTRAINT_ROTATION
\t * 
\t * Define whether port constraint directions are rotated with vertex
\t * rotation. 0 (default) causes port constraints to remain absolute, 
\t * relative to the graph, 1 causes the constraints to rotate with
\t * the vertex. Value is \"portConstraintRotation\".
\t */
\tSTYLE_PORT_CONSTRAINT_ROTATION: 'portConstraintRotation',

\t/**
\t * Variable: STYLE_SOURCE_PORT_CONSTRAINT
\t * 
\t * Defines the direction(s) that edges are allowed to connect to sources in.
\t * Possible values are \"DIRECTION_NORTH, DIRECTION_SOUTH, DIRECTION_EAST\"
\t * and \"DIRECTION_WEST\". Value is \"sourcePortConstraint\".
\t */
\tSTYLE_SOURCE_PORT_CONSTRAINT: 'sourcePortConstraint',

\t/**
\t * Variable: STYLE_TARGET_PORT_CONSTRAINT
\t * 
\t * Defines the direction(s) that edges are allowed to connect to targets in.
\t * Possible values are \"DIRECTION_NORTH, DIRECTION_SOUTH, DIRECTION_EAST\"
\t * and \"DIRECTION_WEST\". Value is \"targetPortConstraint\".
\t */
\tSTYLE_TARGET_PORT_CONSTRAINT: 'targetPortConstraint',

\t/**
\t * Variable: STYLE_OPACITY
\t * 
\t * Defines the key for the opacity style. The type of the value is 
\t * numeric and the possible range is 0-100. Value is \"opacity\".
\t */
\tSTYLE_OPACITY: 'opacity',

\t/**
\t * Variable: STYLE_FILL_OPACITY
\t * 
\t * Defines the key for the fill opacity style. The type of the value is 
\t * numeric and the possible range is 0-100. Value is \"fillOpacity\".
\t */
\tSTYLE_FILL_OPACITY: 'fillOpacity',

\t/**
\t * Variable: STYLE_STROKE_OPACITY
\t * 
\t * Defines the key for the stroke opacity style. The type of the value is 
\t * numeric and the possible range is 0-100. Value is \"strokeOpacity\".
\t */
\tSTYLE_STROKE_OPACITY: 'strokeOpacity',

\t/**
\t * Variable: STYLE_TEXT_OPACITY
\t * 
\t * Defines the key for the text opacity style. The type of the value is 
\t * numeric and the possible range is 0-100. Value is \"textOpacity\".
\t */
\tSTYLE_TEXT_OPACITY: 'textOpacity',

\t/**
\t * Variable: STYLE_TEXT_DIRECTION
\t * 
\t * Defines the key for the text direction style. Possible values are
\t * \"TEXT_DIRECTION_DEFAULT, TEXT_DIRECTION_AUTO, TEXT_DIRECTION_LTR\"
\t * and \"TEXT_DIRECTION_RTL\". Value is \"textDirection\".
\t * The default value for the style is defined in <DEFAULT_TEXT_DIRECTION>.
\t * It is used is no value is defined for this key in a given style. This is
\t * an experimental style that is currently ignored in the backends.
\t */
\tSTYLE_TEXT_DIRECTION: 'textDirection',

\t/**
\t * Variable: STYLE_OVERFLOW
\t * 
\t * Defines the key for the overflow style. Possible values are 'visible',
\t * 'hidden', 'fill' and 'width'. The default value is 'visible'. This value
\t * specifies how overlapping vertex labels are handled. A value of
\t * 'visible' will show the complete label. A value of 'hidden' will clip
\t * the label so that it does not overlap the vertex bounds. A value of
\t * 'fill' will use the vertex bounds and a value of 'width' will use the
\t * vertex width for the label. See <mxGraph.isLabelClipped>. Note that
\t * the vertical alignment is ignored for overflow fill and for horizontal
\t * alignment, left should be used to avoid pixel offsets in Internet Explorer
\t * 11 and earlier or if foreignObjects are disabled. Value is \"overflow\".
\t */
\tSTYLE_OVERFLOW: 'overflow',

\t/**
\t * Variable: STYLE_ORTHOGONAL
\t * 
\t * Defines if the connection points on either end of the edge should be
\t * computed so that the edge is vertical or horizontal if possible and
\t * if the point is not at a fixed location. Default is false. This is
\t * used in <mxGraph.isOrthogonal>, which also returns true if the edgeStyle
\t * of the edge is an elbow or entity. Value is \"orthogonal\".
\t */
\tSTYLE_ORTHOGONAL: 'orthogonal',

\t/**
\t * Variable: STYLE_EXIT_X
\t * 
\t * Defines the key for the horizontal relative coordinate connection point
\t * of an edge with its source terminal. Value is \"exitX\".
\t */
\tSTYLE_EXIT_X: 'exitX',

\t/**
\t * Variable: STYLE_EXIT_Y
\t * 
\t * Defines the key for the vertical relative coordinate connection point
\t * of an edge with its source terminal. Value is \"exitY\".
\t */
\tSTYLE_EXIT_Y: 'exitY',

\t
\t/**
\t* Variable: STYLE_EXIT_DX
\t* 
\t* Defines the key for the horizontal offset of the connection point
\t* of an edge with its source terminal. Value is \"exitDx\".
\t*/
\tSTYLE_EXIT_DX: 'exitDx',

\t/**
\t* Variable: STYLE_EXIT_DY
\t* 
\t* Defines the key for the vertical offset of the connection point
\t* of an edge with its source terminal. Value is \"exitDy\".
\t*/
\tSTYLE_EXIT_DY: 'exitDy',
\t
\t/**
\t * Variable: STYLE_EXIT_PERIMETER
\t * 
\t * Defines if the perimeter should be used to find the exact entry point
\t * along the perimeter of the source. Possible values are 0 (false) and
\t * 1 (true). Default is 1 (true). Value is \"exitPerimeter\".
\t */
\tSTYLE_EXIT_PERIMETER: 'exitPerimeter',

\t/**
\t * Variable: STYLE_ENTRY_X
\t * 
\t * Defines the key for the horizontal relative coordinate connection point
\t * of an edge with its target terminal. Value is \"entryX\".
\t */
\tSTYLE_ENTRY_X: 'entryX',

\t/**
\t * Variable: STYLE_ENTRY_Y
\t * 
\t * Defines the key for the vertical relative coordinate connection point
\t * of an edge with its target terminal. Value is \"entryY\".
\t */
\tSTYLE_ENTRY_Y: 'entryY',

\t/**
\t * Variable: STYLE_ENTRY_DX
\t * 
\t* Defines the key for the horizontal offset of the connection point
\t* of an edge with its target terminal. Value is \"entryDx\".
\t*/
\tSTYLE_ENTRY_DX: 'entryDx',

\t/**
\t * Variable: STYLE_ENTRY_DY
\t * 
\t* Defines the key for the vertical offset of the connection point
\t* of an edge with its target terminal. Value is \"entryDy\".
\t*/
\tSTYLE_ENTRY_DY: 'entryDy',

\t/**
\t * Variable: STYLE_ENTRY_PERIMETER
\t * 
\t * Defines if the perimeter should be used to find the exact entry point
\t * along the perimeter of the target. Possible values are 0 (false) and
\t * 1 (true). Default is 1 (true). Value is \"entryPerimeter\".
\t */
\tSTYLE_ENTRY_PERIMETER: 'entryPerimeter',

\t/**
\t * Variable: STYLE_WHITE_SPACE
\t * 
\t * Defines the key for the white-space style. Possible values are 'nowrap'
\t * and 'wrap'. The default value is 'nowrap'. This value specifies how
\t * white-space inside a HTML vertex label should be handled. A value of
\t * 'nowrap' means the text will never wrap to the next line until a
\t * linefeed is encountered. A value of 'wrap' means text will wrap when
\t * necessary. This style is only used for HTML labels.
\t * See <mxGraph.isWrapping>. Value is \"whiteSpace\".
\t */
\tSTYLE_WHITE_SPACE: 'whiteSpace',

\t/**
\t * Variable: STYLE_ROTATION
\t * 
\t * Defines the key for the rotation style. The type of the value is 
\t * numeric and the possible range is 0-360. Value is \"rotation\".
\t */
\tSTYLE_ROTATION: 'rotation',

\t/**
\t * Variable: STYLE_FILLCOLOR
\t * 
\t * Defines the key for the fill color. Possible values are all HTML color
\t * names or HEX codes, as well as special keywords such as 'swimlane,
\t * 'inherit' or 'indicated' to use the color code of a related cell or the
\t * indicator shape. Value is \"fillColor\".
\t */
\tSTYLE_FILLCOLOR: 'fillColor',

\t/**
\t * Variable: STYLE_POINTER_EVENTS
\t * 
\t * Specifies if pointer events should be fired on transparent backgrounds.
\t * This style is currently only supported in <mxRectangleShape>. Default
\t * is true. Value is \"pointerEvents\". This is typically set to
\t * false in groups where the transparent part should allow any underlying
\t * cells to be clickable.
\t */
\tSTYLE_POINTER_EVENTS: 'pointerEvents',

\t/**
\t * Variable: STYLE_SWIMLANE_FILLCOLOR
\t * 
\t * Defines the key for the fill color of the swimlane background. Possible
\t * values are all HTML color names or HEX codes. Default is no background.
\t * Value is \"swimlaneFillColor\".
\t */
\tSTYLE_SWIMLANE_FILLCOLOR: 'swimlaneFillColor',

\t/**
\t * Variable: STYLE_MARGIN
\t * 
\t * Defines the key for the margin between the ellipses in the double ellipse shape.
\t * Possible values are all positive numbers. Value is \"margin\".
\t */
\tSTYLE_MARGIN: 'margin',

\t/**
\t * Variable: STYLE_GRADIENTCOLOR
\t * 
\t * Defines the key for the gradient color. Possible values are all HTML color
\t * names or HEX codes, as well as special keywords such as 'swimlane,
\t * 'inherit' or 'indicated' to use the color code of a related cell or the
\t * indicator shape. This is ignored if no fill color is defined. Value is
\t * \"gradientColor\".
\t */
\tSTYLE_GRADIENTCOLOR: 'gradientColor',

\t/**
\t * Variable: STYLE_GRADIENT_DIRECTION
\t * 
\t * Defines the key for the gradient direction. Possible values are
\t * <DIRECTION_EAST>, <DIRECTION_WEST>, <DIRECTION_NORTH> and
\t * <DIRECTION_SOUTH>. Default is <DIRECTION_SOUTH>. Generally, and by
\t * default in mxGraph, gradient painting is done from the value of
\t * <STYLE_FILLCOLOR> to the value of <STYLE_GRADIENTCOLOR>. Taking the
\t * example of <DIRECTION_NORTH>, this means <STYLE_FILLCOLOR> color at the 
\t * bottom of paint pattern and <STYLE_GRADIENTCOLOR> at top, with a
\t * gradient in-between. Value is \"gradientDirection\".
\t */
\tSTYLE_GRADIENT_DIRECTION: 'gradientDirection',

\t/**
\t * Variable: STYLE_STROKECOLOR
\t * 
\t * Defines the key for the strokeColor style. Possible values are all HTML
\t * color names or HEX codes, as well as special keywords such as 'swimlane,
\t * 'inherit', 'indicated' to use the color code of a related cell or the
\t * indicator shape or 'none' for no color. Value is \"strokeColor\".
\t */
\tSTYLE_STROKECOLOR: 'strokeColor',

\t/**
\t * Variable: STYLE_SEPARATORCOLOR
\t * 
\t * Defines the key for the separatorColor style. Possible values are all
\t * HTML color names or HEX codes. This style is only used for
\t * <SHAPE_SWIMLANE> shapes. Value is \"separatorColor\".
\t */
\tSTYLE_SEPARATORCOLOR: 'separatorColor',

\t/**
\t * Variable: STYLE_STROKEWIDTH
\t * 
\t * Defines the key for the strokeWidth style. The type of the value is 
\t * numeric and the possible range is any non-negative value larger or equal
\t * to 1. The value defines the stroke width in pixels. Note: To hide a
\t * stroke use strokeColor none. Value is \"strokeWidth\".
\t */
\tSTYLE_STROKEWIDTH: 'strokeWidth',

\t/**
\t * Variable: STYLE_ALIGN
\t * 
\t * Defines the key for the align style. Possible values are <ALIGN_LEFT>,
\t * <ALIGN_CENTER> and <ALIGN_RIGHT>. This value defines how the lines of
\t * the label are horizontally aligned. <ALIGN_LEFT> mean label text lines
\t * are aligned to left of the label bounds, <ALIGN_RIGHT> to the right of
\t * the label bounds and <ALIGN_CENTER> means the center of the text lines
\t * are aligned in the center of the label bounds. Note this value doesn't
\t * affect the positioning of the overall label bounds relative to the
\t * vertex, to move the label bounds horizontally, use
\t * <STYLE_LABEL_POSITION>. Value is \"align\".
\t */
\tSTYLE_ALIGN: 'align',

\t/**
\t * Variable: STYLE_VERTICAL_ALIGN
\t * 
\t * Defines the key for the verticalAlign style. Possible values are
\t * <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>. This value defines how
\t * the lines of the label are vertically aligned. <ALIGN_TOP> means the
\t * topmost label text line is aligned against the top of the label bounds,
\t * <ALIGN_BOTTOM> means the bottom-most label text line is aligned against
\t * the bottom of the label bounds and <ALIGN_MIDDLE> means there is equal
\t * spacing between the topmost text label line and the top of the label
\t * bounds and the bottom-most text label line and the bottom of the label
\t * bounds. Note this value doesn't affect the positioning of the overall
\t * label bounds relative to the vertex, to move the label bounds
\t * vertically, use <STYLE_VERTICAL_LABEL_POSITION>. Value is \"verticalAlign\".
\t */
\tSTYLE_VERTICAL_ALIGN: 'verticalAlign',

\t/**
\t * Variable: STYLE_LABEL_WIDTH
\t * 
\t * Defines the key for the width of the label if the label position is not
\t * center. Value is \"labelWidth\".
\t */
\tSTYLE_LABEL_WIDTH: 'labelWidth',

\t/**
\t * Variable: STYLE_LABEL_POSITION
\t * 
\t * Defines the key for the horizontal label position of vertices. Possible
\t * values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT>. Default is
\t * <ALIGN_CENTER>. The label align defines the position of the label
\t * relative to the cell. <ALIGN_LEFT> means the entire label bounds is
\t * placed completely just to the left of the vertex, <ALIGN_RIGHT> means
\t * adjust to the right and <ALIGN_CENTER> means the label bounds are
\t * vertically aligned with the bounds of the vertex. Note this value
\t * doesn't affect the positioning of label within the label bounds, to move
\t * the label horizontally within the label bounds, use <STYLE_ALIGN>.
\t * Value is \"labelPosition\".
\t */
\tSTYLE_LABEL_POSITION: 'labelPosition',

\t/**
\t * Variable: STYLE_VERTICAL_LABEL_POSITION
\t * 
\t * Defines the key for the vertical label position of vertices. Possible
\t * values are <ALIGN_TOP>, <ALIGN_BOTTOM> and <ALIGN_MIDDLE>. Default is
\t * <ALIGN_MIDDLE>. The label align defines the position of the label
\t * relative to the cell. <ALIGN_TOP> means the entire label bounds is
\t * placed completely just on the top of the vertex, <ALIGN_BOTTOM> means
\t * adjust on the bottom and <ALIGN_MIDDLE> means the label bounds are
\t * horizontally aligned with the bounds of the vertex. Note this value
\t * doesn't affect the positioning of label within the label bounds, to move
\t * the label vertically within the label bounds, use
\t * <STYLE_VERTICAL_ALIGN>. Value is \"verticalLabelPosition\".
\t */
\tSTYLE_VERTICAL_LABEL_POSITION: 'verticalLabelPosition',
\t
\t/**
\t * Variable: STYLE_IMAGE_ASPECT
\t * 
\t * Defines the key for the image aspect style. Possible values are 0 (do
\t * not preserve aspect) or 1 (keep aspect). This is only used in
\t * <mxImageShape>. Default is 1. Value is \"imageAspect\".
\t */
\tSTYLE_IMAGE_ASPECT: 'imageAspect',

\t/**
\t * Variable: STYLE_IMAGE_ALIGN
\t * 
\t * Defines the key for the align style. Possible values are <ALIGN_LEFT>,
\t * <ALIGN_CENTER> and <ALIGN_RIGHT>. The value defines how any image in the
\t * vertex label is aligned horizontally within the label bounds of a
\t * <SHAPE_LABEL> shape. Value is \"imageAlign\".
\t */
\tSTYLE_IMAGE_ALIGN: 'imageAlign',

\t/**
\t * Variable: STYLE_IMAGE_VERTICAL_ALIGN
\t * 
\t * Defines the key for the verticalAlign style. Possible values are
\t * <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>. The value defines how
\t * any image in the vertex label is aligned vertically within the label
\t * bounds of a <SHAPE_LABEL> shape. Value is \"imageVerticalAlign\".
\t */
\tSTYLE_IMAGE_VERTICAL_ALIGN: 'imageVerticalAlign',

\t/**
\t * Variable: STYLE_GLASS
\t * 
\t * Defines the key for the glass style. Possible values are 0 (disabled) and
\t * 1(enabled). The default value is 0. This is used in <mxLabel>. Value is
\t * \"glass\".
\t */
\tSTYLE_GLASS: 'glass',

\t/**
\t * Variable: STYLE_IMAGE
\t * 
\t * Defines the key for the image style. Possible values are any image URL,
\t * the type of the value is String. This is the path to the image that is
\t * to be displayed within the label of a vertex. Data URLs should use the
\t * following format: data:image/png,xyz where xyz is the base64 encoded
\t * data (without the \"base64\"-prefix). Note that Data URLs are only
\t * supported in modern browsers. Value is \"image\".
\t */
\tSTYLE_IMAGE: 'image',

\t/**
\t * Variable: STYLE_IMAGE_WIDTH
\t * 
\t * Defines the key for the imageWidth style. The type of this value is
\t * int, the value is the image width in pixels and must be greater than 0.
\t * Value is \"imageWidth\".
\t */
\tSTYLE_IMAGE_WIDTH: 'imageWidth',

\t/**
\t * Variable: STYLE_IMAGE_HEIGHT
\t * 
\t * Defines the key for the imageHeight style. The type of this value is
\t * int, the value is the image height in pixels and must be greater than 0.
\t * Value is \"imageHeight\".
\t */
\tSTYLE_IMAGE_HEIGHT: 'imageHeight',

\t/**
\t * Variable: STYLE_IMAGE_BACKGROUND
\t * 
\t * Defines the key for the image background color. This style is only used
\t * in <mxImageShape>. Possible values are all HTML color names or HEX
\t * codes. Value is \"imageBackground\".
\t */
\tSTYLE_IMAGE_BACKGROUND: 'imageBackground',

\t/**
\t * Variable: STYLE_IMAGE_BORDER
\t * 
\t * Defines the key for the image border color. This style is only used in
\t * <mxImageShape>. Possible values are all HTML color names or HEX codes.
\t * Value is \"imageBorder\".
\t */
\tSTYLE_IMAGE_BORDER: 'imageBorder',

\t/**
\t * Variable: STYLE_FLIPH
\t * 
\t * Defines the key for the horizontal image flip. This style is only used
\t * in <mxImageShape>. Possible values are 0 and 1. Default is 0. Value is
\t * \"flipH\".
\t */
\tSTYLE_FLIPH: 'flipH',

\t/**
\t * Variable: STYLE_FLIPV
\t * 
\t * Defines the key for the vertical flip. Possible values are 0 and 1.
\t * Default is 0. Value is \"flipV\".
\t */
\tSTYLE_FLIPV: 'flipV',

\t/**
\t * Variable: STYLE_NOLABEL
\t * 
\t * Defines the key for the noLabel style. If this is true then no label is
\t * visible for a given cell. Possible values are true or false (1 or 0).
\t * Default is false. Value is \"noLabel\".
\t */
\tSTYLE_NOLABEL: 'noLabel',

\t/**
\t * Variable: STYLE_NOEDGESTYLE
\t * 
\t * Defines the key for the noEdgeStyle style. If this is true then no edge
\t * style is applied for a given edge. Possible values are true or false
\t * (1 or 0). Default is false. Value is \"noEdgeStyle\".
\t */
\tSTYLE_NOEDGESTYLE: 'noEdgeStyle',

\t/**
\t * Variable: STYLE_LABEL_BACKGROUNDCOLOR
\t * 
\t * Defines the key for the label background color. Possible values are all
\t * HTML color names or HEX codes. Value is \"labelBackgroundColor\".
\t */
\tSTYLE_LABEL_BACKGROUNDCOLOR: 'labelBackgroundColor',

\t/**
\t * Variable: STYLE_LABEL_BORDERCOLOR
\t * 
\t * Defines the key for the label border color. Possible values are all
\t * HTML color names or HEX codes. Value is \"labelBorderColor\".
\t */
\tSTYLE_LABEL_BORDERCOLOR: 'labelBorderColor',

\t/**
\t * Variable: STYLE_LABEL_PADDING
\t * 
\t * Defines the key for the label padding, ie. the space between the label
\t * border and the label. Value is \"labelPadding\".
\t */
\tSTYLE_LABEL_PADDING: 'labelPadding',

\t/**
\t * Variable: STYLE_INDICATOR_SHAPE
\t * 
\t * Defines the key for the indicator shape used within an <mxLabel>.
\t * Possible values are all SHAPE_* constants or the names of any new
\t * shapes. The indicatorShape has precedence over the indicatorImage.
\t * Value is \"indicatorShape\".
\t */
\tSTYLE_INDICATOR_SHAPE: 'indicatorShape',

\t/**
\t * Variable: STYLE_INDICATOR_IMAGE
\t * 
\t * Defines the key for the indicator image used within an <mxLabel>.
\t * Possible values are all image URLs. The indicatorShape has
\t * precedence over the indicatorImage. Value is \"indicatorImage\".
\t */
\tSTYLE_INDICATOR_IMAGE: 'indicatorImage',

\t/**
\t * Variable: STYLE_INDICATOR_COLOR
\t * 
\t * Defines the key for the indicatorColor style. Possible values are all
\t * HTML color names or HEX codes, as well as the special 'swimlane' keyword
\t * to refer to the color of the parent swimlane if one exists. Value is
\t * \"indicatorColor\".
\t */
\tSTYLE_INDICATOR_COLOR: 'indicatorColor',

\t/**
\t * Variable: STYLE_INDICATOR_STROKECOLOR
\t * 
\t * Defines the key for the indicator stroke color in <mxLabel>.
\t * Possible values are all color codes. Value is \"indicatorStrokeColor\".
\t */
\tSTYLE_INDICATOR_STROKECOLOR: 'indicatorStrokeColor',

\t/**
\t * Variable: STYLE_INDICATOR_GRADIENTCOLOR
\t * 
\t * Defines the key for the indicatorGradientColor style. Possible values
\t * are all HTML color names or HEX codes. This style is only supported in
\t * <SHAPE_LABEL> shapes. Value is \"indicatorGradientColor\".
\t */
\tSTYLE_INDICATOR_GRADIENTCOLOR: 'indicatorGradientColor',

\t/**
\t * Variable: STYLE_INDICATOR_SPACING
\t * 
\t * The defines the key for the spacing between the label and the
\t * indicator in <mxLabel>. Possible values are in pixels. Value is
\t * \"indicatorSpacing\".
\t */
\tSTYLE_INDICATOR_SPACING: 'indicatorSpacing',

\t/**
\t * Variable: STYLE_INDICATOR_WIDTH
\t * 
\t * Defines the key for the indicator width. Possible values start at 0 (in
\t * pixels). Value is \"indicatorWidth\".
\t */
\tSTYLE_INDICATOR_WIDTH: 'indicatorWidth',

\t/**
\t * Variable: STYLE_INDICATOR_HEIGHT
\t * 
\t * Defines the key for the indicator height. Possible values start at 0 (in
\t * pixels). Value is \"indicatorHeight\".
\t */
\tSTYLE_INDICATOR_HEIGHT: 'indicatorHeight',

\t/**
\t * Variable: STYLE_INDICATOR_DIRECTION
\t * 
\t * Defines the key for the indicatorDirection style. The direction style is
\t * used to specify the direction of certain shapes (eg. <mxTriangle>).
\t * Possible values are <DIRECTION_EAST> (default), <DIRECTION_WEST>,
\t * <DIRECTION_NORTH> and <DIRECTION_SOUTH>. Value is \"indicatorDirection\".
\t */
\tSTYLE_INDICATOR_DIRECTION: 'indicatorDirection',

\t/**
\t * Variable: STYLE_SHADOW
\t * 
\t * Defines the key for the shadow style. The type of the value is Boolean.
\t * Value is \"shadow\".
\t */
\tSTYLE_SHADOW: 'shadow',
\t
\t/**
\t * Variable: STYLE_SEGMENT
\t * 
\t * Defines the key for the segment style. The type of this value is float
\t * and the value represents the size of the horizontal segment of the
\t * entity relation style. Default is ENTITY_SEGMENT. Value is \"segment\".
\t */
\tSTYLE_SEGMENT: 'segment',
\t
\t/**
\t * Variable: STYLE_ENDARROW
\t *
\t * Defines the key for the end arrow marker. Possible values are all
\t * constants with an ARROW-prefix. This is only used in <mxConnector>.
\t * Value is \"endArrow\".
\t *
\t * Example:
\t * (code)
\t * style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC;
\t * (end)
\t */
\tSTYLE_ENDARROW: 'endArrow',

\t/**
\t * Variable: STYLE_STARTARROW
\t * 
\t * Defines the key for the start arrow marker. Possible values are all
\t * constants with an ARROW-prefix. This is only used in <mxConnector>.
\t * See <STYLE_ENDARROW>. Value is \"startArrow\".
\t */
\tSTYLE_STARTARROW: 'startArrow',

\t/**
\t * Variable: STYLE_ENDSIZE
\t * 
\t * Defines the key for the endSize style. The type of this value is numeric
\t * and the value represents the size of the end marker in pixels. Value is
\t * \"endSize\".
\t */
\tSTYLE_ENDSIZE: 'endSize',

\t/**
\t * Variable: STYLE_STARTSIZE
\t * 
\t * Defines the key for the startSize style. The type of this value is
\t * numeric and the value represents the size of the start marker or the
\t * size of the swimlane title region depending on the shape it is used for.
\t * Value is \"startSize\".
\t */
\tSTYLE_STARTSIZE: 'startSize',

\t/**
\t * Variable: STYLE_SWIMLANE_LINE
\t * 
\t * Defines the key for the swimlaneLine style. This style specifies whether
\t * the line between the title regio of a swimlane should be visible. Use 0
\t * for hidden or 1 (default) for visible. Value is \"swimlaneLine\".
\t */
\tSTYLE_SWIMLANE_LINE: 'swimlaneLine',

\t/**
\t * Variable: STYLE_ENDFILL
\t * 
\t * Defines the key for the endFill style. Use 0 for no fill or 1 (default)
\t * for fill. (This style is only exported via <mxImageExport>.) Value is
\t * \"endFill\".
\t */
\tSTYLE_ENDFILL: 'endFill',

\t/**
\t * Variable: STYLE_STARTFILL
\t * 
\t * Defines the key for the startFill style. Use 0 for no fill or 1 (default)
\t * for fill. (This style is only exported via <mxImageExport>.) Value is
\t * \"startFill\".
\t */
\tSTYLE_STARTFILL: 'startFill',

\t/**
\t * Variable: STYLE_DASHED
\t * 
\t * Defines the key for the dashed style. Use 0 (default) for non-dashed or 1
\t * for dashed. Value is \"dashed\".
\t */
\tSTYLE_DASHED: 'dashed',

\t/**
\t * Variable: STYLE_DASH_PATTERN
\t * 
\t * Defines the key for the dashed pattern style in SVG and image exports.
\t * The type of this value is a space separated list of numbers that specify
\t * a custom-defined dash pattern. Dash styles are defined in terms of the
\t * length of the dash (the drawn part of the stroke) and the length of the
\t * space between the dashes. The lengths are relative to the line width: a
\t * length of \"1\" is equal to the line width. VML ignores this style and
\t * uses dashStyle instead as defined in the VML specification. This style
\t * is only used in the <mxConnector> shape. Value is \"dashPattern\".
\t */
\tSTYLE_DASH_PATTERN: 'dashPattern',

\t/**
\t * Variable: STYLE_FIX_DASH
\t * 
\t * Defines the key for the fixDash style. Use 0 (default) for dash patterns
\t * that depend on the linewidth and 1 for dash patterns that ignore the
\t * line width. Value is \"fixDash\".
\t */
\tSTYLE_FIX_DASH: 'fixDash',

\t/**
\t * Variable: STYLE_ROUNDED
\t * 
\t * Defines the key for the rounded style. The type of this value is
\t * Boolean. For edges this determines whether or not joins between edges
\t * segments are smoothed to a rounded finish. For vertices that have the
\t * rectangle shape, this determines whether or not the rectangle is
\t * rounded. Use 0 (default) for non-rounded or 1 for rounded. Value is
\t * \"rounded\".
\t */
\tSTYLE_ROUNDED: 'rounded',

\t/**
\t * Variable: STYLE_CURVED
\t * 
\t * Defines the key for the curved style. The type of this value is
\t * Boolean. It is only applicable for connector shapes. Use 0 (default)
\t * for non-curved or 1 for curved. Value is \"curved\".
\t */
\tSTYLE_CURVED: 'curved',

\t/**
\t * Variable: STYLE_ARCSIZE
\t * 
\t * Defines the rounding factor for a rounded rectangle in percent (without
\t * the percent sign). Possible values are between 0 and 100. If this value
\t * is not specified then RECTANGLE_ROUNDING_FACTOR * 100 is used. For
\t * edges, this defines the absolute size of rounded corners in pixels. If
\t * this values is not specified then LINE_ARCSIZE is used.
\t * (This style is only exported via <mxImageExport>.) Value is \"arcSize\".
\t */
\tSTYLE_ARCSIZE: 'arcSize',

\t/**
\t * Variable: STYLE_ABSOLUTE_ARCSIZE
\t * 
\t * Defines the key for the absolute arc size style. This specifies if
\t * arcSize for rectangles is abolute or relative. Possible values are 1
\t * and 0 (default). Value is \"absoluteArcSize\".
\t */
\tSTYLE_ABSOLUTE_ARCSIZE: 'absoluteArcSize',

\t/**
\t * Variable: STYLE_SOURCE_PERIMETER_SPACING
\t * 
\t * Defines the key for the source perimeter spacing. The type of this value
\t * is numeric. This is the distance between the source connection point of
\t * an edge and the perimeter of the source vertex in pixels. This style
\t * only applies to edges. Value is \"sourcePerimeterSpacing\".
\t */
\tSTYLE_SOURCE_PERIMETER_SPACING: 'sourcePerimeterSpacing',

\t/**
\t * Variable: STYLE_TARGET_PERIMETER_SPACING
\t * 
\t * Defines the key for the target perimeter spacing. The type of this value
\t * is numeric. This is the distance between the target connection point of
\t * an edge and the perimeter of the target vertex in pixels. This style
\t * only applies to edges. Value is \"targetPerimeterSpacing\".
\t */
\tSTYLE_TARGET_PERIMETER_SPACING: 'targetPerimeterSpacing',

\t/**
\t * Variable: STYLE_PERIMETER_SPACING
\t * 
\t * Defines the key for the perimeter spacing. This is the distance between
\t * the connection point and the perimeter in pixels. When used in a vertex
\t * style, this applies to all incoming edges to floating ports (edges that
\t * terminate on the perimeter of the vertex). When used in an edge style,
\t * this spacing applies to the source and target separately, if they
\t * terminate in floating ports (on the perimeter of the vertex). Value is
\t * \"perimeterSpacing\".
\t */
\tSTYLE_PERIMETER_SPACING: 'perimeterSpacing',

\t/**
\t * Variable: STYLE_SPACING
\t * 
\t * Defines the key for the spacing. The value represents the spacing, in
\t * pixels, added to each side of a label in a vertex (style applies to
\t * vertices only). Value is \"spacing\".
\t */
\tSTYLE_SPACING: 'spacing',

\t/**
\t * Variable: STYLE_SPACING_TOP
\t * 
\t * Defines the key for the spacingTop style. The value represents the
\t * spacing, in pixels, added to the top side of a label in a vertex (style
\t * applies to vertices only). Value is \"spacingTop\".
\t */
\tSTYLE_SPACING_TOP: 'spacingTop',

\t/**
\t * Variable: STYLE_SPACING_LEFT
\t * 
\t * Defines the key for the spacingLeft style. The value represents the
\t * spacing, in pixels, added to the left side of a label in a vertex (style
\t * applies to vertices only). Value is \"spacingLeft\".
\t */
\tSTYLE_SPACING_LEFT: 'spacingLeft',

\t/**
\t * Variable: STYLE_SPACING_BOTTOM
\t * 
\t * Defines the key for the spacingBottom style The value represents the
\t * spacing, in pixels, added to the bottom side of a label in a vertex
\t * (style applies to vertices only). Value is \"spacingBottom\".
\t */
\tSTYLE_SPACING_BOTTOM: 'spacingBottom',

\t/**
\t * Variable: STYLE_SPACING_RIGHT
\t * 
\t * Defines the key for the spacingRight style The value represents the
\t * spacing, in pixels, added to the right side of a label in a vertex (style
\t * applies to vertices only). Value is \"spacingRight\".
\t */
\tSTYLE_SPACING_RIGHT: 'spacingRight',

\t/**
\t * Variable: STYLE_HORIZONTAL
\t * 
\t * Defines the key for the horizontal style. Possible values are
\t * true or false. This value only applies to vertices. If the <STYLE_SHAPE>
\t * is \"SHAPE_SWIMLANE\" a value of false indicates that the
\t * swimlane should be drawn vertically, true indicates to draw it
\t * horizontally. If the shape style does not indicate that this vertex is a
\t * swimlane, this value affects only whether the label is drawn
\t * horizontally or vertically. Value is \"horizontal\".
\t */
\tSTYLE_HORIZONTAL: 'horizontal',

\t/**
\t * Variable: STYLE_DIRECTION
\t * 
\t * Defines the key for the direction style. The direction style is used
\t * to specify the direction of certain shapes (eg. <mxTriangle>).
\t * Possible values are <DIRECTION_EAST> (default), <DIRECTION_WEST>,
\t * <DIRECTION_NORTH> and <DIRECTION_SOUTH>. Value is \"direction\".
\t */
\tSTYLE_DIRECTION: 'direction',

\t/**
\t * Variable: STYLE_ANCHOR_POINT_DIRECTION
\t * 
\t * Defines the key for the anchorPointDirection style. The defines if the
\t * direction style should be taken into account when computing the fixed
\t * point location for connected edges. Default is 1 (yes). Set this to 0
\t * to ignore the direction style for fixed connection points. Value is
\t * \"anchorPointDirection\".
\t */
\tSTYLE_ANCHOR_POINT_DIRECTION: 'anchorPointDirection',

\t/**
\t * Variable: STYLE_ELBOW
\t * 
\t * Defines the key for the elbow style. Possible values are
\t * <ELBOW_HORIZONTAL> and <ELBOW_VERTICAL>. Default is <ELBOW_HORIZONTAL>.
\t * This defines how the three segment orthogonal edge style leaves its
\t * terminal vertices. The vertical style leaves the terminal vertices at
\t * the top and bottom sides. Value is \"elbow\".
\t */
\tSTYLE_ELBOW: 'elbow',

\t/**
\t * Variable: STYLE_FONTCOLOR
\t * 
\t * Defines the key for the fontColor style. Possible values are all HTML
\t * color names or HEX codes. Value is \"fontColor\".
\t */
\tSTYLE_FONTCOLOR: 'fontColor',

\t/**
\t * Variable: STYLE_FONTFAMILY
\t * 
\t * Defines the key for the fontFamily style. Possible values are names such
\t * as Arial; Dialog; Verdana; Times New Roman. The value is of type String.
\t * Value is fontFamily.
\t */
\tSTYLE_FONTFAMILY: 'fontFamily',

\t/**
\t * Variable: STYLE_FONTSIZE
\t * 
\t * Defines the key for the fontSize style (in px). The type of the value
\t * is int. Value is \"fontSize\".
\t */
\tSTYLE_FONTSIZE: 'fontSize',

\t/**
\t * Variable: STYLE_FONTSTYLE
\t * 
\t * Defines the key for the fontStyle style. Values may be any logical AND
\t * (sum) of <FONT_BOLD>, <FONT_ITALIC> and <FONT_UNDERLINE>.
\t * The type of the value is int. Value is \"fontStyle\".
\t */
\tSTYLE_FONTSTYLE: 'fontStyle',
\t
\t/**
\t * Variable: STYLE_ASPECT
\t * 
\t * Defines the key for the aspect style. Possible values are empty or fixed.
\t * If fixed is used then the aspect ratio of the cell will be maintained
\t * when resizing. Default is empty. Value is \"aspect\".
\t */
\tSTYLE_ASPECT: 'aspect',

\t/**
\t * Variable: STYLE_AUTOSIZE
\t * 
\t * Defines the key for the autosize style. This specifies if a cell should be
\t * resized automatically if the value has changed. Possible values are 0 or 1.
\t * Default is 0. See <mxGraph.isAutoSizeCell>. This is normally combined with
\t * <STYLE_RESIZABLE> to disable manual sizing. Value is \"autosize\".
\t */
\tSTYLE_AUTOSIZE: 'autosize',

\t/**
\t * Variable: STYLE_FOLDABLE
\t * 
\t * Defines the key for the foldable style. This specifies if a cell is foldable
\t * using a folding icon. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellFoldable>. Value is \"foldable\".
\t */
\tSTYLE_FOLDABLE: 'foldable',

\t/**
\t * Variable: STYLE_EDITABLE
\t * 
\t * Defines the key for the editable style. This specifies if the value of
\t * a cell can be edited using the in-place editor. Possible values are 0 or
\t * 1. Default is 1. See <mxGraph.isCellEditable>. Value is \"editable\".
\t */
\tSTYLE_EDITABLE: 'editable',

\t/**
\t * Variable: STYLE_BACKGROUND_OUTLINE
\t * 
\t * Defines the key for the backgroundOutline style. This specifies if a
\t * only the background of a cell should be painted when it is highlighted.
\t * Possible values are 0 or 1. Default is 0. Value is \"backgroundOutline\".
\t */
\tSTYLE_BACKGROUND_OUTLINE: 'backgroundOutline',

\t/**
\t * Variable: STYLE_BENDABLE
\t * 
\t * Defines the key for the bendable style. This specifies if the control
\t * points of an edge can be moved. Possible values are 0 or 1. Default is
\t * 1. See <mxGraph.isCellBendable>. Value is \"bendable\".
\t */
\tSTYLE_BENDABLE: 'bendable',

\t/**
\t * Variable: STYLE_MOVABLE
\t * 
\t * Defines the key for the movable style. This specifies if a cell can
\t * be moved. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellMovable>. Value is \"movable\".
\t */
\tSTYLE_MOVABLE: 'movable',

\t/**
\t * Variable: STYLE_RESIZABLE
\t * 
\t * Defines the key for the resizable style. This specifies if a cell can
\t * be resized. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellResizable>. Value is \"resizable\".
\t */
\tSTYLE_RESIZABLE: 'resizable',

\t/**
\t * Variable: STYLE_RESIZE_WIDTH
\t * 
\t * Defines the key for the resizeWidth style. This specifies if a cell's
\t * width is resized if the parent is resized. If this is 1 then the width
\t * will be resized even if the cell's geometry is relative. If this is 0
\t * then the cell's width will not be resized. Default is not defined. Value
\t * is \"resizeWidth\".
\t */
\tSTYLE_RESIZE_WIDTH: 'resizeWidth',

\t/**
\t * Variable: STYLE_RESIZE_WIDTH
\t * 
\t * Defines the key for the resizeHeight style. This specifies if a cell's
\t * height if resize if the parent is resized. If this is 1 then the height
\t * will be resized even if the cell's geometry is relative. If this is 0
\t * then the cell's height will not be resized. Default is not defined. Value
\t * is \"resizeHeight\".
\t */
\tSTYLE_RESIZE_HEIGHT: 'resizeHeight',

\t/**
\t * Variable: STYLE_ROTATABLE
\t * 
\t * Defines the key for the rotatable style. This specifies if a cell can
\t * be rotated. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellRotatable>. Value is \"rotatable\".
\t */
\tSTYLE_ROTATABLE: 'rotatable',

\t/**
\t * Variable: STYLE_CLONEABLE
\t * 
\t * Defines the key for the cloneable style. This specifies if a cell can
\t * be cloned. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellCloneable>. Value is \"cloneable\".
\t */
\tSTYLE_CLONEABLE: 'cloneable',

\t/**
\t * Variable: STYLE_DELETABLE
\t * 
\t * Defines the key for the deletable style. This specifies if a cell can be
\t * deleted. Possible values are 0 or 1. Default is 1. See
\t * <mxGraph.isCellDeletable>. Value is \"deletable\".
\t */
\tSTYLE_DELETABLE: 'deletable',

\t/**
\t * Variable: STYLE_SHAPE
\t * 
\t * Defines the key for the shape. Possible values are all constants with
\t * a SHAPE-prefix or any newly defined shape names. Value is \"shape\".
\t */
\tSTYLE_SHAPE: 'shape',

\t/**
\t * Variable: STYLE_EDGE
\t * 
\t * Defines the key for the edge style. Possible values are the functions
\t * defined in <mxEdgeStyle>. Value is \"edgeStyle\".
\t */
\tSTYLE_EDGE: 'edgeStyle',

\t/**
\t * Variable: STYLE_JETTY_SIZE
\t * 
\t * Defines the key for the jetty size in <mxEdgeStyle.OrthConnector>.
\t * Default is 10. Possible values are all numeric values or \"auto\".
\t * Jetty size is the minimum length of the orthogonal segment before
\t * it attaches to a shape.
\t * Value is \"jettySize\".
\t */
\tSTYLE_JETTY_SIZE: 'jettySize',

\t/**
\t * Variable: STYLE_SOURCE_JETTY_SIZE
\t * 
\t * Defines the key for the jetty size in <mxEdgeStyle.OrthConnector>.
\t * Default is 10. Possible values are numeric values or \"auto\". This has
\t * precedence over <STYLE_JETTY_SIZE>. Value is \"sourceJettySize\".
\t */
\tSTYLE_SOURCE_JETTY_SIZE: 'sourceJettySize',

\t/**
\t * Variable: targetJettySize
\t * 
\t * Defines the key for the jetty size in <mxEdgeStyle.OrthConnector>.
\t * Default is 10. Possible values are numeric values or \"auto\". This has
\t * precedence over <STYLE_JETTY_SIZE>. Value is \"targetJettySize\".
\t */
\tSTYLE_TARGET_JETTY_SIZE: 'targetJettySize',

\t/**
\t * Variable: STYLE_LOOP
\t * 
\t * Defines the key for the loop style. Possible values are the functions
\t * defined in <mxEdgeStyle>. Value is \"loopStyle\". Default is
\t * <mxGraph.defaultLoopStylean>.
\t */
\tSTYLE_LOOP: 'loopStyle',

\t/**
\t * Variable: STYLE_ORTHOGONAL_LOOP
\t * 
\t * Defines the key for the orthogonal loop style. Possible values are 0 and
\t * 1. Default is 0. Value is \"orthogonalLoop\". Use this style to specify
\t * if loops with no waypoints and defined anchor points should be routed
\t * using <STYLE_LOOP> or not routed.
\t */
\tSTYLE_ORTHOGONAL_LOOP: 'orthogonalLoop',

\t/**
\t * Variable: STYLE_ROUTING_CENTER_X
\t * 
\t * Defines the key for the horizontal routing center. Possible values are
\t * between -0.5 and 0.5. This is the relative offset from the center used
\t * for connecting edges. The type of this value is numeric. Value is
\t * \"routingCenterX\".
\t */
\tSTYLE_ROUTING_CENTER_X: 'routingCenterX',

\t/**
\t * Variable: STYLE_ROUTING_CENTER_Y
\t * 
\t * Defines the key for the vertical routing center. Possible values are
\t * between -0.5 and 0.5. This is the relative offset from the center used
\t * for connecting edges. The type of this value is numeric. Value is
\t * \"routingCenterY\".
\t */
\tSTYLE_ROUTING_CENTER_Y: 'routingCenterY',

\t/**
\t * Variable: FONT_BOLD
\t * 
\t * Constant for bold fonts. Default is 1.
\t */
\tFONT_BOLD: 1,

\t/**
\t * Variable: FONT_ITALIC
\t * 
\t * Constant for italic fonts. Default is 2.
\t */
\tFONT_ITALIC: 2,

\t/**
\t * Variable: FONT_UNDERLINE
\t * 
\t * Constant for underlined fonts. Default is 4.
\t */
\tFONT_UNDERLINE: 4,

\t/**
\t * Variable: FONT_STRIKETHROUGH
\t * 
\t * Constant for strikthrough fonts. Default is 8.
\t */
\tFONT_STRIKETHROUGH: 8,
\t
\t/**
\t * Variable: SHAPE_RECTANGLE
\t * 
\t * Name under which <mxRectangleShape> is registered in <mxCellRenderer>.
\t * Default is rectangle.
\t */
\tSHAPE_RECTANGLE: 'rectangle',

\t/**
\t * Variable: SHAPE_ELLIPSE
\t * 
\t * Name under which <mxEllipse> is registered in <mxCellRenderer>.
\t * Default is ellipse.
\t */
\tSHAPE_ELLIPSE: 'ellipse',

\t/**
\t * Variable: SHAPE_DOUBLE_ELLIPSE
\t * 
\t * Name under which <mxDoubleEllipse> is registered in <mxCellRenderer>.
\t * Default is doubleEllipse.
\t */
\tSHAPE_DOUBLE_ELLIPSE: 'doubleEllipse',

\t/**
\t * Variable: SHAPE_RHOMBUS
\t * 
\t * Name under which <mxRhombus> is registered in <mxCellRenderer>.
\t * Default is rhombus.
\t */
\tSHAPE_RHOMBUS: 'rhombus',

\t/**
\t * Variable: SHAPE_LINE
\t * 
\t * Name under which <mxLine> is registered in <mxCellRenderer>.
\t * Default is line.
\t */
\tSHAPE_LINE: 'line',

\t/**
\t * Variable: SHAPE_IMAGE
\t * 
\t * Name under which <mxImageShape> is registered in <mxCellRenderer>.
\t * Default is image.
\t */
\tSHAPE_IMAGE: 'image',
\t
\t/**
\t * Variable: SHAPE_ARROW
\t * 
\t * Name under which <mxArrow> is registered in <mxCellRenderer>.
\t * Default is arrow.
\t */
\tSHAPE_ARROW: 'arrow',
\t
\t/**
\t * Variable: SHAPE_ARROW_CONNECTOR
\t * 
\t * Name under which <mxArrowConnector> is registered in <mxCellRenderer>.
\t * Default is arrowConnector.
\t */
\tSHAPE_ARROW_CONNECTOR: 'arrowConnector',
\t
\t/**
\t * Variable: SHAPE_LABEL
\t * 
\t * Name under which <mxLabel> is registered in <mxCellRenderer>.
\t * Default is label.
\t */
\tSHAPE_LABEL: 'label',
\t
\t/**
\t * Variable: SHAPE_CYLINDER
\t * 
\t * Name under which <mxCylinder> is registered in <mxCellRenderer>.
\t * Default is cylinder.
\t */
\tSHAPE_CYLINDER: 'cylinder',
\t
\t/**
\t * Variable: SHAPE_SWIMLANE
\t * 
\t * Name under which <mxSwimlane> is registered in <mxCellRenderer>.
\t * Default is swimlane.
\t */
\tSHAPE_SWIMLANE: 'swimlane',
\t\t
\t/**
\t * Variable: SHAPE_CONNECTOR
\t * 
\t * Name under which <mxConnector> is registered in <mxCellRenderer>.
\t * Default is connector.
\t */
\tSHAPE_CONNECTOR: 'connector',

\t/**
\t * Variable: SHAPE_ACTOR
\t * 
\t * Name under which <mxActor> is registered in <mxCellRenderer>.
\t * Default is actor.
\t */
\tSHAPE_ACTOR: 'actor',
\t\t
\t/**
\t * Variable: SHAPE_CLOUD
\t * 
\t * Name under which <mxCloud> is registered in <mxCellRenderer>.
\t * Default is cloud.
\t */
\tSHAPE_CLOUD: 'cloud',
\t\t
\t/**
\t * Variable: SHAPE_TRIANGLE
\t * 
\t * Name under which <mxTriangle> is registered in <mxCellRenderer>.
\t * Default is triangle.
\t */
\tSHAPE_TRIANGLE: 'triangle',
\t\t
\t/**
\t * Variable: SHAPE_HEXAGON
\t * 
\t * Name under which <mxHexagon> is registered in <mxCellRenderer>.
\t * Default is hexagon.
\t */
\tSHAPE_HEXAGON: 'hexagon',

\t/**
\t * Variable: ARROW_CLASSIC
\t * 
\t * Constant for classic arrow markers.
\t */
\tARROW_CLASSIC: 'classic',

\t/**
\t * Variable: ARROW_CLASSIC_THIN
\t * 
\t * Constant for thin classic arrow markers.
\t */
\tARROW_CLASSIC_THIN: 'classicThin',

\t/**
\t * Variable: ARROW_BLOCK
\t * 
\t * Constant for block arrow markers.
\t */
\tARROW_BLOCK: 'block',

\t/**
\t * Variable: ARROW_BLOCK_THIN
\t * 
\t * Constant for thin block arrow markers.
\t */
\tARROW_BLOCK_THIN: 'blockThin',

\t/**
\t * Variable: ARROW_OPEN
\t * 
\t * Constant for open arrow markers.
\t */
\tARROW_OPEN: 'open',

\t/**
\t * Variable: ARROW_OPEN_THIN
\t * 
\t * Constant for thin open arrow markers.
\t */
\tARROW_OPEN_THIN: 'openThin',

\t/**
\t * Variable: ARROW_OVAL
\t * 
\t * Constant for oval arrow markers.
\t */
\tARROW_OVAL: 'oval',

\t/**
\t * Variable: ARROW_DIAMOND
\t * 
\t * Constant for diamond arrow markers.
\t */
\tARROW_DIAMOND: 'diamond',

\t/**
\t * Variable: ARROW_DIAMOND_THIN
\t * 
\t * Constant for thin diamond arrow markers.
\t */
\tARROW_DIAMOND_THIN: 'diamondThin',

\t/**
\t * Variable: ALIGN_LEFT
\t * 
\t * Constant for left horizontal alignment. Default is left.
\t */
\tALIGN_LEFT: 'left',

\t/**
\t * Variable: ALIGN_CENTER
\t * 
\t * Constant for center horizontal alignment. Default is center.
\t */
\tALIGN_CENTER: 'center',

\t/**
\t * Variable: ALIGN_RIGHT
\t * 
\t * Constant for right horizontal alignment. Default is right.
\t */
\tALIGN_RIGHT: 'right',

\t/**
\t * Variable: ALIGN_TOP
\t * 
\t * Constant for top vertical alignment. Default is top.
\t */
\tALIGN_TOP: 'top',

\t/**
\t * Variable: ALIGN_MIDDLE
\t * 
\t * Constant for middle vertical alignment. Default is middle.
\t */
\tALIGN_MIDDLE: 'middle',

\t/**
\t * Variable: ALIGN_BOTTOM
\t * 
\t * Constant for bottom vertical alignment. Default is bottom.
\t */
\tALIGN_BOTTOM: 'bottom',

\t/**
\t * Variable: DIRECTION_NORTH
\t * 
\t * Constant for direction north. Default is north.
\t */
\tDIRECTION_NORTH: 'north',

\t/**
\t * Variable: DIRECTION_SOUTH
\t * 
\t * Constant for direction south. Default is south.
\t */
\tDIRECTION_SOUTH: 'south',

\t/**
\t * Variable: DIRECTION_EAST
\t * 
\t * Constant for direction east. Default is east.
\t */
\tDIRECTION_EAST: 'east',

\t/**
\t * Variable: DIRECTION_WEST
\t * 
\t * Constant for direction west. Default is west.
\t */
\tDIRECTION_WEST: 'west',

\t/**
\t * Variable: TEXT_DIRECTION_DEFAULT
\t * 
\t * Constant for text direction default. Default is an empty string. Use
\t * this value to use the default text direction of the operating system. 
\t */
\tTEXT_DIRECTION_DEFAULT: '',

\t/**
\t * Variable: TEXT_DIRECTION_AUTO
\t * 
\t * Constant for text direction automatic. Default is auto. Use this value
\t * to find the direction for a given text with <mxText.getAutoDirection>. 
\t */
\tTEXT_DIRECTION_AUTO: 'auto',

\t/**
\t * Variable: TEXT_DIRECTION_LTR
\t * 
\t * Constant for text direction left to right. Default is ltr. Use this
\t * value for left to right text direction.
\t */
\tTEXT_DIRECTION_LTR: 'ltr',

\t/**
\t * Variable: TEXT_DIRECTION_RTL
\t * 
\t * Constant for text direction right to left. Default is rtl. Use this
\t * value for right to left text direction.
\t */
\tTEXT_DIRECTION_RTL: 'rtl',

\t/**
\t * Variable: DIRECTION_MASK_NONE
\t * 
\t * Constant for no direction.
\t */
\tDIRECTION_MASK_NONE: 0,

\t/**
\t * Variable: DIRECTION_MASK_WEST
\t * 
\t * Bitwise mask for west direction.
\t */
\tDIRECTION_MASK_WEST: 1,
\t
\t/**
\t * Variable: DIRECTION_MASK_NORTH
\t * 
\t * Bitwise mask for north direction.
\t */
\tDIRECTION_MASK_NORTH: 2,

\t/**
\t * Variable: DIRECTION_MASK_SOUTH
\t * 
\t * Bitwise mask for south direction.
\t */
\tDIRECTION_MASK_SOUTH: 4,

\t/**
\t * Variable: DIRECTION_MASK_EAST
\t * 
\t * Bitwise mask for east direction.
\t */
\tDIRECTION_MASK_EAST: 8,
\t
\t/**
\t * Variable: DIRECTION_MASK_ALL
\t * 
\t * Bitwise mask for all directions.
\t */
\tDIRECTION_MASK_ALL: 15,

\t/**
\t * Variable: ELBOW_VERTICAL
\t * 
\t * Constant for elbow vertical. Default is horizontal.
\t */
\tELBOW_VERTICAL: 'vertical',

\t/**
\t * Variable: ELBOW_HORIZONTAL
\t * 
\t * Constant for elbow horizontal. Default is horizontal.
\t */
\tELBOW_HORIZONTAL: 'horizontal',

\t/**
\t * Variable: EDGESTYLE_ELBOW
\t * 
\t * Name of the elbow edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_ELBOW: 'elbowEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_ENTITY_RELATION
\t * 
\t * Name of the entity relation edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_ENTITY_RELATION: 'entityRelationEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_LOOP
\t * 
\t * Name of the loop edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_LOOP: 'loopEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_SIDETOSIDE
\t * 
\t * Name of the side to side edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_SIDETOSIDE: 'sideToSideEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_TOPTOBOTTOM
\t * 
\t * Name of the top to bottom edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_TOPTOBOTTOM: 'topToBottomEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_ORTHOGONAL
\t * 
\t * Name of the generic orthogonal edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_ORTHOGONAL: 'orthogonalEdgeStyle',

\t/**
\t * Variable: EDGESTYLE_SEGMENT
\t * 
\t * Name of the generic segment edge style. Can be used as a string value
\t * for the STYLE_EDGE style.
\t */
\tEDGESTYLE_SEGMENT: 'segmentEdgeStyle',
 
\t/**
\t * Variable: PERIMETER_ELLIPSE
\t * 
\t * Name of the ellipse perimeter. Can be used as a string value
\t * for the STYLE_PERIMETER style.
\t */
\tPERIMETER_ELLIPSE: 'ellipsePerimeter',

\t/**
\t * Variable: PERIMETER_RECTANGLE
\t *
\t * Name of the rectangle perimeter. Can be used as a string value
\t * for the STYLE_PERIMETER style.
\t */
\tPERIMETER_RECTANGLE: 'rectanglePerimeter',

\t/**
\t * Variable: PERIMETER_RHOMBUS
\t * 
\t * Name of the rhombus perimeter. Can be used as a string value
\t * for the STYLE_PERIMETER style.
\t */
\tPERIMETER_RHOMBUS: 'rhombusPerimeter',

\t/**
\t * Variable: PERIMETER_HEXAGON
\t * 
\t * Name of the hexagon perimeter. Can be used as a string value 
\t * for the STYLE_PERIMETER style.
\t */
\tPERIMETER_HEXAGON: 'hexagonPerimeter',

\t/**
\t * Variable: PERIMETER_TRIANGLE
\t * 
\t * Name of the triangle perimeter. Can be used as a string value
\t * for the STYLE_PERIMETER style.
\t */
\tPERIMETER_TRIANGLE: 'trianglePerimeter'
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxEventObject
 * 
 * The mxEventObject is a wrapper for all properties of a single event.
 * Additionally, it also offers functions to consume the event and check if it
 * was consumed as follows:
 * 
 * (code)
 * evt.consume();
 * INV: evt.isConsumed() == true
 * (end)
 * 
 * Constructor: mxEventObject
 *
 * Constructs a new event object with the specified name. An optional
 * sequence of key, value pairs can be appended to define properties.
 * 
 * Example:
 *
 * (code)
 * new mxEventObject(\"eventName\", key1, val1, .., keyN, valN)
 * (end)
 */
function mxEventObject(name)
{
\tthis.name = name;
\tthis.properties = [];
\t
\tfor (var i = 1; i < arguments.length; i += 2)
\t{
\t\tif (arguments[i + 1] != null)
\t\t{
\t\t\tthis.properties[arguments[i]] = arguments[i + 1];
\t\t}
\t}
};

/**
 * Variable: name
 *
 * Holds the name.
 */
mxEventObject.prototype.name = null;

/**
 * Variable: properties
 *
 * Holds the properties as an associative array.
 */
mxEventObject.prototype.properties = null;

/**
 * Variable: consumed
 *
 * Holds the consumed state. Default is false.
 */
mxEventObject.prototype.consumed = false;

/**
 * Function: getName
 * 
 * Returns <name>.
 */
mxEventObject.prototype.getName = function()
{
\treturn this.name;
};

/**
 * Function: getProperties
 * 
 * Returns <properties>.
 */
mxEventObject.prototype.getProperties = function()
{
\treturn this.properties;
};

/**
 * Function: getProperty
 * 
 * Returns the property for the given key.
 */
mxEventObject.prototype.getProperty = function(key)
{
\treturn this.properties[key];
};

/**
 * Function: isConsumed
 *
 * Returns true if the event has been consumed.
 */
mxEventObject.prototype.isConsumed = function()
{
\treturn this.consumed;
};

/**
 * Function: consume
 *
 * Consumes the event.
 */
mxEventObject.prototype.consume = function()
{
\tthis.consumed = true;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxMouseEvent
 * 
 * Base class for all mouse events in mxGraph. A listener for this event should
 * implement the following methods:
 * 
 * (code)
 * graph.addMouseListener(
 * {
 *   mouseDown: function(sender, evt)
 *   {
 *     mxLog.debug('mouseDown');
 *   },
 *   mouseMove: function(sender, evt)
 *   {
 *     mxLog.debug('mouseMove');
 *   },
 *   mouseUp: function(sender, evt)
 *   {
 *     mxLog.debug('mouseUp');
 *   }
 * });
 * (end)
 * 
 * Constructor: mxMouseEvent
 *
 * Constructs a new event object for the given arguments.
 * 
 * Parameters:
 * 
 * evt - Native mouse event.
 * state - Optional <mxCellState> under the mouse.
 * 
 */
function mxMouseEvent(evt, state)
{
\tthis.evt = evt;
\tthis.state = state;
\tthis.sourceState = state;
};

/**
 * Variable: consumed
 *
 * Holds the consumed state of this event.
 */
mxMouseEvent.prototype.consumed = false;

/**
 * Variable: evt
 *
 * Holds the inner event object.
 */
mxMouseEvent.prototype.evt = null;

/**
 * Variable: graphX
 *
 * Holds the x-coordinate of the event in the graph. This value is set in
 * <mxGraph.fireMouseEvent>.
 */
mxMouseEvent.prototype.graphX = null;

/**
 * Variable: graphY
 *
 * Holds the y-coordinate of the event in the graph. This value is set in
 * <mxGraph.fireMouseEvent>.
 */
mxMouseEvent.prototype.graphY = null;

/**
 * Variable: state
 *
 * Holds the optional <mxCellState> associated with this event.
 */
mxMouseEvent.prototype.state = null;

/**
 * Variable: sourceState
 * 
 * Holds the <mxCellState> that was passed to the constructor. This can be
 * different from <state> depending on the result of <mxGraph.getEventState>.
 */
mxMouseEvent.prototype.sourceState = null;

/**
 * Function: getEvent
 * 
 * Returns <evt>.
 */
mxMouseEvent.prototype.getEvent = function()
{
\treturn this.evt;
};

/**
 * Function: getSource
 * 
 * Returns the target DOM element using <mxEvent.getSource> for <evt>.
 */
mxMouseEvent.prototype.getSource = function()
{
\treturn mxEvent.getSource(this.evt);
};

/**
 * Function: isSource
 * 
 * Returns true if the given <mxShape> is the source of <evt>.
 */
mxMouseEvent.prototype.isSource = function(shape)
{
\tif (shape != null)
\t{
\t\treturn mxUtils.isAncestorNode(shape.node, this.getSource());
\t}
\t
\treturn false;
};

/**
 * Function: getX
 * 
 * Returns <evt.clientX>.
 */
mxMouseEvent.prototype.getX = function()
{
\treturn mxEvent.getClientX(this.getEvent());
};

/**
 * Function: getY
 * 
 * Returns <evt.clientY>.
 */
mxMouseEvent.prototype.getY = function()
{
\treturn mxEvent.getClientY(this.getEvent());
};

/**
 * Function: getGraphX
 * 
 * Returns <graphX>.
 */
mxMouseEvent.prototype.getGraphX = function()
{
\treturn this.graphX;
};

/**
 * Function: getGraphY
 * 
 * Returns <graphY>.
 */
mxMouseEvent.prototype.getGraphY = function()
{
\treturn this.graphY;
};

/**
 * Function: getState
 * 
 * Returns <state>.
 */
mxMouseEvent.prototype.getState = function()
{
\treturn this.state;
};

/**
 * Function: getCell
 * 
 * Returns the <mxCell> in <state> is not null.
 */
mxMouseEvent.prototype.getCell = function()
{
\tvar state = this.getState();
\t
\tif (state != null)
\t{
\t\treturn state.cell;
\t}
\t
\treturn null;
};

/**
 * Function: isPopupTrigger
 *
 * Returns true if the event is a popup trigger.
 */
mxMouseEvent.prototype.isPopupTrigger = function()
{
\treturn mxEvent.isPopupTrigger(this.getEvent());
};

/**
 * Function: isConsumed
 *
 * Returns <consumed>.
 */
mxMouseEvent.prototype.isConsumed = function()
{
\treturn this.consumed;
};

/**
 * Function: consume
 *
 * Sets <consumed> to true and invokes preventDefault on the native event
 * if such a method is defined. This is used mainly to avoid the cursor from
 * being changed to a text cursor in Webkit. You can use the preventDefault
 * flag to disable this functionality.
 * 
 * Parameters:
 * 
 * preventDefault - Specifies if the native event should be canceled. Default
 * is true.
 */
mxMouseEvent.prototype.consume = function(preventDefault)
{
\tpreventDefault = (preventDefault != null) ? preventDefault :
\t\t(this.evt.touches != null || mxEvent.isMouseEvent(this.evt));
\t
\tif (preventDefault && this.evt.preventDefault)
\t{
\t\tthis.evt.preventDefault();
\t}

\t// Workaround for images being dragged in IE
\t// Does not change returnValue in Opera
\tif (mxClient.IS_IE)
\t{
\t\tthis.evt.returnValue = true;
\t}

\t// Sets local consumed state
\tthis.consumed = true;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxEventSource
 *
 * Base class for objects that dispatch named events. To create a subclass that
 * inherits from mxEventSource, the following code is used.
 *
 * (code)
 * function MyClass() { };
 *
 * MyClass.prototype = new mxEventSource();
 * MyClass.prototype.constructor = MyClass;
 * (end)
 *
 * Known Subclasses:
 *
 * <mxGraphModel>, <mxGraph>, <mxGraphView>, <mxEditor>, <mxCellOverlay>,
 * <mxToolbar>, <mxWindow>
 * 
 * Constructor: mxEventSource
 *
 * Constructs a new event source.
 */
function mxEventSource(eventSource)
{
\tthis.setEventSource(eventSource);
};

/**
 * Variable: eventListeners
 *
 * Holds the event names and associated listeners in an array. The array
 * contains the event name followed by the respective listener for each
 * registered listener.
 */
mxEventSource.prototype.eventListeners = null;

/**
 * Variable: eventsEnabled
 *
 * Specifies if events can be fired. Default is true.
 */
mxEventSource.prototype.eventsEnabled = true;

/**
 * Variable: eventSource
 *
 * Optional source for events. Default is null.
 */
mxEventSource.prototype.eventSource = null;

/**
 * Function: isEventsEnabled
 * 
 * Returns <eventsEnabled>.
 */
mxEventSource.prototype.isEventsEnabled = function()
{
\treturn this.eventsEnabled;
};

/**
 * Function: setEventsEnabled
 * 
 * Sets <eventsEnabled>.
 */
mxEventSource.prototype.setEventsEnabled = function(value)
{
\tthis.eventsEnabled = value;
};

/**
 * Function: getEventSource
 * 
 * Returns <eventSource>.
 */
mxEventSource.prototype.getEventSource = function()
{
\treturn this.eventSource;
};

/**
 * Function: setEventSource
 * 
 * Sets <eventSource>.
 */
mxEventSource.prototype.setEventSource = function(value)
{
\tthis.eventSource = value;
};

/**
 * Function: addListener
 *
 * Binds the specified function to the given event name. If no event name
 * is given, then the listener is registered for all events.
 * 
 * The parameters of the listener are the sender and an <mxEventObject>.
 */
mxEventSource.prototype.addListener = function(name, funct)
{
\tif (this.eventListeners == null)
\t{
\t\tthis.eventListeners = [];
\t}
\t
\tthis.eventListeners.push(name);
\tthis.eventListeners.push(funct);
};

/**
 * Function: removeListener
 *
 * Removes all occurrences of the given listener from <eventListeners>.
 */
mxEventSource.prototype.removeListener = function(funct)
{
\tif (this.eventListeners != null)
\t{
\t\tvar i = 0;
\t\t
\t\twhile (i < this.eventListeners.length)
\t\t{
\t\t\tif (this.eventListeners[i+1] == funct)
\t\t\t{
\t\t\t\tthis.eventListeners.splice(i, 2);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\ti += 2;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: fireEvent
 *
 * Dispatches the given event to the listeners which are registered for
 * the event. The sender argument is optional. The current execution scope
 * (\"this\") is used for the listener invocation (see <mxUtils.bind>).
 *
 * Example:
 *
 * (code)
 * fireEvent(new mxEventObject(\"eventName\", key1, val1, .., keyN, valN))
 * (end)
 * 
 * Parameters:
 *
 * evt - <mxEventObject> that represents the event.
 * sender - Optional sender to be passed to the listener. Default value is
 * the return value of <getEventSource>.
 */
mxEventSource.prototype.fireEvent = function(evt, sender)
{
\tif (this.eventListeners != null && this.isEventsEnabled())
\t{
\t\tif (evt == null)
\t\t{
\t\t\tevt = new mxEventObject();
\t\t}
\t\t
\t\tif (sender == null)
\t\t{
\t\t\tsender = this.getEventSource();
\t\t}

\t\tif (sender == null)
\t\t{
\t\t\tsender = this;
\t\t}

\t\tvar args = [sender, evt];
\t\t
\t\tfor (var i = 0; i < this.eventListeners.length; i += 2)
\t\t{
\t\t\tvar listen = this.eventListeners[i];
\t\t\t
\t\t\tif (listen == null || listen == evt.getName())
\t\t\t{
\t\t\t\tthis.eventListeners[i+1].apply(this, args);
\t\t\t}
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxEvent =
{

\t/**
\t * Class: mxEvent
\t * 
\t * Cross-browser DOM event support. For internal event handling,
\t * <mxEventSource> and the graph event dispatch loop in <mxGraph> are used.
\t * 
\t * Memory Leaks:
\t * 
\t * Use this class for adding and removing listeners to/from DOM nodes. The
\t * <removeAllListeners> function is provided to remove all listeners that
\t * have been added using <addListener>. The function should be invoked when
\t * the last reference is removed in the JavaScript code, typically when the
\t * referenced DOM node is removed from the DOM.
\t *
\t * Function: addListener
\t * 
\t * Binds the function to the specified event on the given element. Use
\t * <mxUtils.bind> in order to bind the \"this\" keyword inside the function
\t * to a given execution scope.
\t */
\taddListener: function()
\t{
\t\tvar updateListenerList = function(element, eventName, funct)
\t\t{
\t\t\tif (element.mxListenerList == null)
\t\t\t{
\t\t\t\telement.mxListenerList = [];
\t\t\t}
\t\t\t
\t\t\tvar entry = {name: eventName, f: funct};
\t\t\telement.mxListenerList.push(entry);
\t\t};
\t\t
\t\tif (window.addEventListener)
\t\t{
\t\t\treturn function(element, eventName, funct)
\t\t\t{
\t\t\t\telement.addEventListener(eventName, funct, false);
\t\t\t\tupdateListenerList(element, eventName, funct);
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function(element, eventName, funct)
\t\t\t{
\t\t\t\telement.attachEvent('on' + eventName, funct);
\t\t\t\tupdateListenerList(element, eventName, funct);\t\t\t\t
\t\t\t};
\t\t}
\t}(),

\t/**
\t * Function: removeListener
\t *
\t * Removes the specified listener from the given element.
\t */
\tremoveListener: function()
\t{
\t\tvar updateListener = function(element, eventName, funct)
\t\t{
\t\t\tif (element.mxListenerList != null)
\t\t\t{
\t\t\t\tvar listenerCount = element.mxListenerList.length;
\t\t\t\t
\t\t\t\tfor (var i = 0; i < listenerCount; i++)
\t\t\t\t{
\t\t\t\t\tvar entry = element.mxListenerList[i];
\t\t\t\t\t
\t\t\t\t\tif (entry.f == funct)
\t\t\t\t\t{
\t\t\t\t\t\telement.mxListenerList.splice(i, 1);
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (element.mxListenerList.length == 0)
\t\t\t\t{
\t\t\t\t\telement.mxListenerList = null;
\t\t\t\t}
\t\t\t}
\t\t};
\t\t
\t\tif (window.removeEventListener)
\t\t{
\t\t\treturn function(element, eventName, funct)
\t\t\t{
\t\t\t\telement.removeEventListener(eventName, funct, false);
\t\t\t\tupdateListener(element, eventName, funct);
\t\t\t};
\t\t}
\t\telse
\t\t{
\t\t\treturn function(element, eventName, funct)
\t\t\t{
\t\t\t\telement.detachEvent('on' + eventName, funct);
\t\t\t\tupdateListener(element, eventName, funct);
\t\t\t};
\t\t}
\t}(),

\t/**
\t * Function: removeAllListeners
\t * 
\t * Removes all listeners from the given element.
\t */
\tremoveAllListeners: function(element)
\t{
\t\tvar list = element.mxListenerList;

\t\tif (list != null)
\t\t{
\t\t\twhile (list.length > 0)
\t\t\t{
\t\t\t\tvar entry = list[0];
\t\t\t\tmxEvent.removeListener(element, entry.name, entry.f);
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: addGestureListeners
\t * 
\t * Adds the given listeners for touch, mouse and/or pointer events. If
\t * <mxClient.IS_POINTER> is true then pointer events will be registered,
\t * else the respective mouse events will be registered. If <mxClient.IS_POINTER>
\t * is false and <mxClient.IS_TOUCH> is true then the respective touch events
\t * will be registered as well as the mouse events.
\t */
\taddGestureListeners: function(node, startListener, moveListener, endListener)
\t{
\t\tif (startListener != null)
\t\t{
\t\t\tmxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', startListener);
\t\t}
\t\t
\t\tif (moveListener != null)
\t\t{
\t\t\tmxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', moveListener);
\t\t}
\t\t
\t\tif (endListener != null)
\t\t{
\t\t\tmxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', endListener);
\t\t}
\t\t
\t\tif (!mxClient.IS_POINTER && mxClient.IS_TOUCH)
\t\t{
\t\t\tif (startListener != null)
\t\t\t{
\t\t\t\tmxEvent.addListener(node, 'touchstart', startListener);
\t\t\t}
\t\t\t
\t\t\tif (moveListener != null)
\t\t\t{
\t\t\t\tmxEvent.addListener(node, 'touchmove', moveListener);
\t\t\t}
\t\t\t
\t\t\tif (endListener != null)
\t\t\t{
\t\t\t\tmxEvent.addListener(node, 'touchend', endListener);
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: removeGestureListeners
\t * 
\t * Removes the given listeners from mousedown, mousemove, mouseup and the
\t * respective touch events if <mxClient.IS_TOUCH> is true.
\t */
\tremoveGestureListeners: function(node, startListener, moveListener, endListener)
\t{
\t\tif (startListener != null)
\t\t{
\t\t\tmxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', startListener);
\t\t}
\t\t
\t\tif (moveListener != null)
\t\t{
\t\t\tmxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', moveListener);
\t\t}
\t\t
\t\tif (endListener != null)
\t\t{
\t\t\tmxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', endListener);
\t\t}
\t\t
\t\tif (!mxClient.IS_POINTER && mxClient.IS_TOUCH)
\t\t{
\t\t\tif (startListener != null)
\t\t\t{
\t\t\t\tmxEvent.removeListener(node, 'touchstart', startListener);
\t\t\t}
\t\t\t
\t\t\tif (moveListener != null)
\t\t\t{
\t\t\t\tmxEvent.removeListener(node, 'touchmove', moveListener);
\t\t\t}
\t\t\t
\t\t\tif (endListener != null)
\t\t\t{
\t\t\t\tmxEvent.removeListener(node, 'touchend', endListener);
\t\t\t}
\t\t}
\t},
\t
\t/**
\t * Function: redirectMouseEvents
\t *
\t * Redirects the mouse events from the given DOM node to the graph dispatch
\t * loop using the event and given state as event arguments. State can
\t * either be an instance of <mxCellState> or a function that returns an
\t * <mxCellState>. The down, move, up and dblClick arguments are optional
\t * functions that take the trigger event as arguments and replace the
\t * default behaviour.
\t */
\tredirectMouseEvents: function(node, graph, state, down, move, up, dblClick)
\t{
\t\tvar getState = function(evt)
\t\t{
\t\t\treturn (typeof(state) == 'function') ? state(evt) : state;
\t\t};
\t\t
\t\tmxEvent.addGestureListeners(node, function (evt)
\t\t{
\t\t\tif (down != null)
\t\t\t{
\t\t\t\tdown(evt);
\t\t\t}
\t\t\telse if (!mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t},
\t\tfunction (evt)
\t\t{
\t\t\tif (move != null)
\t\t\t{
\t\t\t\tmove(evt);
\t\t\t}
\t\t\telse if (!mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t},
\t\tfunction (evt)
\t\t{
\t\t\tif (up != null)
\t\t\t{
\t\t\t\tup(evt);
\t\t\t}
\t\t\telse if (!mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t});

\t\tmxEvent.addListener(node, 'dblclick', function (evt)
\t\t{
\t\t\tif (dblClick != null)
\t\t\t{
\t\t\t\tdblClick(evt);
\t\t\t}
\t\t\telse if (!mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tvar tmp = getState(evt);
\t\t\t\tgraph.dblClick(evt, (tmp != null) ? tmp.cell : null);
\t\t\t}
\t\t});
\t},

\t/**
\t * Function: release
\t * 
\t * Removes the known listeners from the given DOM node and its descendants.
\t * 
\t * Parameters:
\t * 
\t * element - DOM node to remove the listeners from.
\t */
\trelease: function(element)
\t{
\t\ttry
\t\t{
\t\t\tif (element != null)
\t\t\t{
\t\t\t\tmxEvent.removeAllListeners(element);
\t\t\t\t
\t\t\t\tvar children = element.childNodes;
\t\t\t\t
\t\t\t\tif (children != null)
\t\t\t\t{
\t\t\t        var childCount = children.length;
\t\t\t        
\t\t\t        for (var i = 0; i < childCount; i += 1)
\t\t\t        {
\t\t\t        \tmxEvent.release(children[i]);
\t\t\t        }
\t\t\t    }
\t\t\t}
\t\t}
\t\tcatch (e)
\t\t{
\t\t\t// ignores errors as this is typically called in cleanup code
\t\t}
\t},

\t/**
\t * Function: addMouseWheelListener
\t * 
\t * Installs the given function as a handler for mouse wheel events. The
\t * function has two arguments: the mouse event and a boolean that specifies
\t * if the wheel was moved up or down.
\t * 
\t * This has been tested with IE 6 and 7, Firefox (all versions), Opera and
\t * Safari. It does currently not work on Safari for Mac.
\t * 
\t * Example:
\t * 
\t * (code)
\t * mxEvent.addMouseWheelListener(function (evt, up, pinch)
\t * {
\t *   mxLog.show();
\t *   mxLog.debug('mouseWheel: up='+up);
\t * });
\t *(end)
\t * 
\t * Parameters:
\t * 
\t * funct - Handler function that takes the event argument, a boolean argument
\t * for the mousewheel direction and a boolean to specify if the underlying
\t * event was a pinch gesture on a touch device.
\t * target - Target for installing the listener in Google Chrome. See 
\t * https://www.chromestatus.com/features/6662647093133312.
\t */
\taddMouseWheelListener: function(funct, target)
\t{
\t\tif (funct != null)
\t\t{
\t\t\tvar wheelHandler = function(evt)
\t\t\t{
\t\t\t\t// IE does not give an event object but the
\t\t\t\t// global event object is the mousewheel event
\t\t\t\t// at this point in time.
\t\t\t\tif (evt == null)
\t\t\t\t{
\t\t\t\t\tevt = window.event;
\t\t\t\t}
\t\t\t
\t\t\t\t//To prevent window zoom on trackpad pinch
\t\t\t\tif (evt.ctrlKey) 
\t\t\t\t{
\t\t\t\t\tevt.preventDefault();
\t\t\t\t}

\t\t\t\tvar delta = -evt.deltaY;
\t\t\t\t
\t\t\t\t// Handles the event using the given function
\t\t\t\tif (Math.abs(evt.deltaX) > 0.5 || Math.abs(evt.deltaY) > 0.5)
\t\t\t\t{
\t\t\t\t\tfunct(evt, (evt.deltaY == 0) ?  -evt.deltaX > 0 : -evt.deltaY > 0);
\t\t\t\t}
\t\t\t};
\t
\t\t\ttarget = target != null ? target : window;
\t\t\t\t\t
\t\t\tif (mxClient.IS_SF && !mxClient.IS_TOUCH)
\t\t\t{
\t\t\t\tvar scale = 1;
\t\t\t\t
\t\t\t\tmxEvent.addListener(target, 'gesturestart', function(evt)
\t\t\t\t{
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t\tscale = 1;
\t\t\t\t});
\t\t\t\t
\t\t\t\tmxEvent.addListener(target, 'gesturechange', function(evt)
\t\t\t\t{
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t\tvar diff = scale - evt.scale;
\t\t\t\t\t
\t\t\t\t\tif (Math.abs(diff) > 0.2)
\t\t\t\t\t{
\t\t\t\t\t\tfunct(evt, diff < 0, true);
\t\t\t\t\t\tscale = evt.scale;
\t\t\t\t\t}
\t\t\t\t});

\t\t\t\tmxEvent.addListener(target, 'gestureend', function(evt)
\t\t\t\t{
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t});
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar evtCache = [];
\t\t\t\tvar dx0 = 0;
\t\t\t\tvar dy0 = 0;
\t\t\t\t
\t\t\t\t// Adds basic listeners for graph event dispatching
\t\t\t\tmxEvent.addGestureListeners(target, mxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tif (!mxEvent.isMouseEvent(evt) && evt.pointerId != null)
\t\t\t\t\t{
\t\t\t\t\t\tevtCache.push(evt);
\t\t\t\t\t}
\t\t\t\t}),
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tif (!mxEvent.isMouseEvent(evt) && evtCache.length == 2)
\t\t\t\t\t{
\t\t\t\t\t\t// Find this event in the cache and update its record with this event
\t\t\t\t\t\tfor (var i = 0; i < evtCache.length; i++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (evt.pointerId == evtCache[i].pointerId)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tevtCache[i] = evt;
\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t   \t// Calculate the distance between the two pointers
\t\t\t\t\t\tvar dx = Math.abs(evtCache[0].clientX - evtCache[1].clientX);
\t\t\t\t\t\tvar dy = Math.abs(evtCache[0].clientY - evtCache[1].clientY);
\t\t\t\t\t\tvar tx = Math.abs(dx - dx0);
\t\t\t\t\t\tvar ty = Math.abs(dy - dy0);
\t\t\t\t\t
\t\t\t\t\t\tif (tx > mxEvent.PINCH_THRESHOLD || ty > mxEvent.PINCH_THRESHOLD)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar cx = evtCache[0].clientX + (evtCache[1].clientX - evtCache[0].clientX) / 2;
\t\t\t\t\t\t\tvar cy = evtCache[0].clientY + (evtCache[1].clientY - evtCache[0].clientY) / 2;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tfunct(evtCache[0], (tx > ty) ? dx > dx0 : dy > dy0, true, cx, cy);
\t\t\t\t\t\t
\t\t\t\t\t\t   \t// Cache the distance for the next move event 
\t\t\t\t\t\t\tdx0 = dx;
\t\t\t\t\t\t\tdy0 = dy;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}),
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tevtCache = [];
\t\t\t\t\tdx0 = 0;
\t\t\t\t\tdy0 = 0;
\t\t\t\t}));
\t\t\t}
\t\t\t
\t\t\tmxEvent.addListener(target, 'wheel', wheelHandler);
\t\t}
\t},
\t
\t/**
\t * Function: disableContextMenu
\t *
\t * Disables the context menu for the given element.
\t */
\tdisableContextMenu: function(element)
\t{
\t\tmxEvent.addListener(element, 'contextmenu', function(evt)
\t\t{
\t\t\tif (evt.preventDefault)
\t\t\t{
\t\t\t\tevt.preventDefault();
\t\t\t}
\t\t\t
\t\t\treturn false;
\t\t});
\t},
\t
\t/**
\t * Function: getSource
\t * 
\t * Returns the event's target or srcElement depending on the browser.
\t */
\tgetSource: function(evt)
\t{
\t\treturn (evt.srcElement != null) ? evt.srcElement : evt.target;
\t},

\t/**
\t * Function: isConsumed
\t * 
\t * Returns true if the event has been consumed using <consume>.
\t */
\tisConsumed: function(evt)
\t{
\t\treturn evt.isConsumed != null && evt.isConsumed;
\t},

\t/**
\t * Function: isTouchEvent
\t * 
\t * Returns true if the event was generated using a touch device (not a pen or mouse).
\t */
\tisTouchEvent: function(evt)
\t{
\t\treturn (evt.pointerType != null) ? (evt.pointerType == 'touch' || evt.pointerType ===
\t\t\tevt.MSPOINTER_TYPE_TOUCH) : ((evt.mozInputSource != null) ?
\t\t\t\t\tevt.mozInputSource == 5 : evt.type.indexOf('touch') == 0);
\t},

\t/**
\t * Function: isPenEvent
\t * 
\t * Returns true if the event was generated using a pen (not a touch device or mouse).
\t */
\tisPenEvent: function(evt)
\t{
\t\treturn (evt.pointerType != null) ? (evt.pointerType == 'pen' || evt.pointerType ===
\t\t\tevt.MSPOINTER_TYPE_PEN) : ((evt.mozInputSource != null) ?
\t\t\t\t\tevt.mozInputSource == 2 : evt.type.indexOf('pen') == 0);
\t},

\t/**
\t * Function: isMultiTouchEvent
\t * 
\t * Returns true if the event was generated using a touch device (not a pen or mouse).
\t */
\tisMultiTouchEvent: function(evt)
\t{
\t\treturn (evt.type != null && evt.type.indexOf('touch') == 0 && evt.touches != null && evt.touches.length > 1);
\t},

\t/**
\t * Function: isMouseEvent
\t * 
\t * Returns true if the event was generated using a mouse (not a pen or touch device).
\t */
\tisMouseEvent: function(evt)
\t{
\t\treturn (evt.pointerType != null) ? (evt.pointerType == 'mouse' || evt.pointerType ===
\t\t\tevt.MSPOINTER_TYPE_MOUSE) : ((evt.mozInputSource != null) ?
\t\t\t\tevt.mozInputSource == 1 : evt.type.indexOf('mouse') == 0);
\t},
\t
\t/**
\t * Function: isLeftMouseButton
\t * 
\t * Returns true if the left mouse button is pressed for the given event.
\t * To check if a button is pressed during a mouseMove you should use the
\t * <mxGraph.isMouseDown> property. Note that this returns true in Firefox
\t * for control+left-click on the Mac.
\t */
\tisLeftMouseButton: function(evt)
\t{
\t\t// Special case for mousemove and mousedown we check the buttons
\t\t// if it exists because which is 0 even if no button is pressed
\t\tif ('buttons' in evt && (evt.type == 'mousedown' || evt.type == 'mousemove'))
\t\t{
\t\t\treturn evt.buttons == 1;
\t\t}
\t\telse if ('which' in evt)
\t\t{
\t        return evt.which === 1;
\t    }
\t\telse
\t\t{
\t        return evt.button === 1;
\t    }
\t},
\t
\t/**
\t * Function: isMiddleMouseButton
\t * 
\t * Returns true if the middle mouse button is pressed for the given event.
\t * To check if a button is pressed during a mouseMove you should use the
\t * <mxGraph.isMouseDown> property.
\t */
\tisMiddleMouseButton: function(evt)
\t{
\t\tif ('which' in evt)
\t\t{
\t        return evt.which === 2;
\t    }
\t\telse
\t\t{
\t        return evt.button === 4;
\t    }
\t},
\t
\t/**
\t * Function: isRightMouseButton
\t * 
\t * Returns true if the right mouse button was pressed. Note that this
\t * button might not be available on some systems. For handling a popup
\t * trigger <isPopupTrigger> should be used.
\t */
\tisRightMouseButton: function(evt)
\t{
\t\tif ('which' in evt)
\t\t{
\t        return evt.which === 3;
\t    }
\t\telse
\t\t{
\t        return evt.button === 2;
\t    }
\t},

\t/**
\t * Function: isPopupTrigger
\t * 
\t * Returns true if the event is a popup trigger. This implementation
\t * returns true if the right button or the left button and control was
\t * pressed on a Mac.
\t */
\tisPopupTrigger: function(evt)
\t{
\t\treturn mxEvent.isRightMouseButton(evt) || (mxClient.IS_MAC && mxEvent.isControlDown(evt) &&
\t\t\t!mxEvent.isShiftDown(evt) && !mxEvent.isMetaDown(evt) && !mxEvent.isAltDown(evt));
\t},

\t/**
\t * Function: isShiftDown
\t * 
\t * Returns true if the shift key is pressed for the given event.
\t */
\tisShiftDown: function(evt)
\t{
\t\treturn (evt != null) ? evt.shiftKey : false;
\t},

\t/**
\t * Function: isAltDown
\t * 
\t * Returns true if the alt key is pressed for the given event.
\t */
\tisAltDown: function(evt)
\t{
\t\treturn (evt != null) ? evt.altKey : false;
\t},

\t/**
\t * Function: isControlDown
\t * 
\t * Returns true if the control key is pressed for the given event.
\t */
\tisControlDown: function(evt)
\t{
\t\treturn (evt != null) ? evt.ctrlKey : false;
\t},

\t/**
\t * Function: isMetaDown
\t * 
\t * Returns true if the meta key is pressed for the given event.
\t */
\tisMetaDown: function(evt)
\t{
\t\treturn (evt != null) ? evt.metaKey : false;
\t},

\t/**
\t * Function: getMainEvent
\t * 
\t * Returns the touch or mouse event that contains the mouse coordinates.
\t */
\tgetMainEvent: function(e)
\t{
\t\tif ((e.type == 'touchstart' || e.type == 'touchmove') && e.touches != null && e.touches[0] != null)
\t\t{
\t\t\te = e.touches[0];
\t\t}
\t\telse if (e.type == 'touchend' && e.changedTouches != null && e.changedTouches[0] != null)
\t\t{
\t\t\te = e.changedTouches[0];
\t\t}
\t\t
\t\treturn e;
\t},
\t
\t/**
\t * Function: getClientX
\t * 
\t * Returns true if the meta key is pressed for the given event.
\t */
\tgetClientX: function(e)
\t{
\t\treturn mxEvent.getMainEvent(e).clientX;
\t},

\t/**
\t * Function: getClientY
\t * 
\t * Returns true if the meta key is pressed for the given event.
\t */
\tgetClientY: function(e)
\t{
\t\treturn mxEvent.getMainEvent(e).clientY;
\t},

\t/**
\t * Function: consume
\t * 
\t * Consumes the given event.
\t * 
\t * Parameters:
\t * 
\t * evt - Native event to be consumed.
\t * preventDefault - Optional boolean to prevent the default for the event.
\t * Default is true.
\t * stopPropagation - Option boolean to stop event propagation. Default is
\t * true.
\t */
\tconsume: function(evt, preventDefault, stopPropagation)
\t{
\t\tpreventDefault = (preventDefault != null) ? preventDefault : true;
\t\tstopPropagation = (stopPropagation != null) ? stopPropagation : true;
\t\t
\t\tif (preventDefault)
\t\t{
\t\t\tif (evt.preventDefault)
\t\t\t{
\t\t\t\tif (stopPropagation)
\t\t\t\t{
\t\t\t\t\tevt.stopPropagation();
\t\t\t\t}
\t\t\t\t
\t\t\t\tevt.preventDefault();
\t\t\t}
\t\t\telse if (stopPropagation)
\t\t\t{
\t\t\t\tevt.cancelBubble = true;
\t\t\t}
\t\t}

\t\t// Opera
\t\tevt.isConsumed = true;

\t\t// Other browsers
\t\tif (!evt.preventDefault)
\t\t{
\t\t\tevt.returnValue = false;
\t\t}
\t},
\t
\t//
\t// Special handles in mouse events
\t//
\t
\t/**
\t * Variable: LABEL_HANDLE
\t * 
\t * Index for the label handle in an mxMouseEvent. This should be a negative
\t * value that does not interfere with any possible handle indices. Default
\t * is -1.
\t */
\tLABEL_HANDLE: -1,
\t
\t/**
\t * Variable: ROTATION_HANDLE
\t * 
\t * Index for the rotation handle in an mxMouseEvent. This should be a
\t * negative value that does not interfere with any possible handle indices.
\t * Default is -2.
\t */
\tROTATION_HANDLE: -2,
\t
\t/**
\t * Variable: CUSTOM_HANDLE
\t * 
\t * Start index for the custom handles in an mxMouseEvent. This should be a
\t * negative value and is the start index which is decremented for each
\t * custom handle. Default is -100.
\t */
\tCUSTOM_HANDLE: -100,
\t
\t/**
\t * Variable: VIRTUAL_HANDLE
\t * 
\t * Start index for the virtual handles in an mxMouseEvent. This should be a
\t * negative value and is the start index which is decremented for each
\t * virtual handle. Default is -100000. This assumes that there are no more
\t * than VIRTUAL_HANDLE - CUSTOM_HANDLE custom handles.
\t * 
\t */
\tVIRTUAL_HANDLE: -100000,
\t
\t//
\t// Event names
\t//
\t
\t/**
\t * Variable: MOUSE_DOWN
\t *
\t * Specifies the event name for mouseDown.
\t */
\tMOUSE_DOWN: 'mouseDown',
\t
\t/**
\t * Variable: MOUSE_MOVE
\t *
\t * Specifies the event name for mouseMove. 
\t */
\tMOUSE_MOVE: 'mouseMove',
\t
\t/**
\t * Variable: MOUSE_UP
\t *
\t * Specifies the event name for mouseUp. 
\t */
\tMOUSE_UP: 'mouseUp',

\t/**
\t * Variable: ACTIVATE
\t *
\t * Specifies the event name for activate.
\t */
\tACTIVATE: 'activate',

\t/**
\t * Variable: RESIZE_START
\t *
\t * Specifies the event name for resizeStart.
\t */
\tRESIZE_START: 'resizeStart',

\t/**
\t * Variable: RESIZE
\t *
\t * Specifies the event name for resize.
\t */
\tRESIZE: 'resize',

\t/**
\t * Variable: RESIZE_END
\t *
\t * Specifies the event name for resizeEnd.
\t */
\tRESIZE_END: 'resizeEnd',

\t/**
\t * Variable: MOVE_START
\t *
\t * Specifies the event name for moveStart.
\t */
\tMOVE_START: 'moveStart',

\t/**
\t * Variable: MOVE
\t *
\t * Specifies the event name for move.
\t */
\tMOVE: 'move',

\t/**
\t * Variable: MOVE_END
\t *
\t * Specifies the event name for moveEnd.
\t */
\tMOVE_END: 'moveEnd',

\t/**
\t * Variable: PAN_START
\t *
\t * Specifies the event name for panStart.
\t */
\tPAN_START: 'panStart',

\t/**
\t * Variable: PAN
\t *
\t * Specifies the event name for pan.
\t */
\tPAN: 'pan',

\t/**
\t * Variable: PAN_END
\t *
\t * Specifies the event name for panEnd.
\t */
\tPAN_END: 'panEnd',

\t/**
\t * Variable: MINIMIZE
\t *
\t * Specifies the event name for minimize.
\t */
\tMINIMIZE: 'minimize',

\t/**
\t * Variable: NORMALIZE
\t *
\t * Specifies the event name for normalize.
\t */
\tNORMALIZE: 'normalize',

\t/**
\t * Variable: MAXIMIZE
\t *
\t * Specifies the event name for maximize.
\t */
\tMAXIMIZE: 'maximize',

\t/**
\t * Variable: HIDE
\t *
\t * Specifies the event name for hide.
\t */
\tHIDE: 'hide',

\t/**
\t * Variable: SHOW
\t *
\t * Specifies the event name for show.
\t */
\tSHOW: 'show',

\t/**
\t * Variable: CLOSE
\t *
\t * Specifies the event name for close.
\t */
\tCLOSE: 'close',

\t/**
\t * Variable: DESTROY
\t *
\t * Specifies the event name for destroy.
\t */
\tDESTROY: 'destroy',

\t/**
\t * Variable: REFRESH
\t *
\t * Specifies the event name for refresh.
\t */
\tREFRESH: 'refresh',

\t/**
\t * Variable: SIZE
\t *
\t * Specifies the event name for size.
\t */
\tSIZE: 'size',
\t
\t/**
\t * Variable: SELECT
\t *
\t * Specifies the event name for select.
\t */
\tSELECT: 'select',

\t/**
\t * Variable: FIRED
\t *
\t * Specifies the event name for fired.
\t */
\tFIRED: 'fired',

\t/**
\t * Variable: FIRE_MOUSE_EVENT
\t *
\t * Specifies the event name for fireMouseEvent.
\t */
\tFIRE_MOUSE_EVENT: 'fireMouseEvent',

\t/**
\t * Variable: GESTURE
\t *
\t * Specifies the event name for gesture.
\t */
\tGESTURE: 'gesture',

\t/**
\t * Variable: TAP_AND_HOLD
\t *
\t * Specifies the event name for tapAndHold.
\t */
\tTAP_AND_HOLD: 'tapAndHold',

\t/**
\t * Variable: GET
\t *
\t * Specifies the event name for get.
\t */
\tGET: 'get',

\t/**
\t * Variable: RECEIVE
\t *
\t * Specifies the event name for receive.
\t */
\tRECEIVE: 'receive',

\t/**
\t * Variable: CONNECT
\t *
\t * Specifies the event name for connect.
\t */
\tCONNECT: 'connect',

\t/**
\t * Variable: DISCONNECT
\t *
\t * Specifies the event name for disconnect.
\t */
\tDISCONNECT: 'disconnect',

\t/**
\t * Variable: SUSPEND
\t *
\t * Specifies the event name for suspend.
\t */
\tSUSPEND: 'suspend',

\t/**
\t * Variable: RESUME
\t *
\t * Specifies the event name for suspend.
\t */
\tRESUME: 'resume',

\t/**
\t * Variable: MARK
\t *
\t * Specifies the event name for mark.
\t */
\tMARK: 'mark',

\t/**
\t * Variable: ROOT
\t *
\t * Specifies the event name for root.
\t */
\tROOT: 'root',

\t/**
\t * Variable: POST
\t *
\t * Specifies the event name for post.
\t */
\tPOST: 'post',

\t/**
\t * Variable: OPEN
\t *
\t * Specifies the event name for open.
\t */
\tOPEN: 'open',

\t/**
\t * Variable: SAVE
\t *
\t * Specifies the event name for open.
\t */
\tSAVE: 'save',

\t/**
\t * Variable: BEFORE_ADD_VERTEX
\t *
\t * Specifies the event name for beforeAddVertex.
\t */
\tBEFORE_ADD_VERTEX: 'beforeAddVertex',

\t/**
\t * Variable: ADD_VERTEX
\t *
\t * Specifies the event name for addVertex.
\t */
\tADD_VERTEX: 'addVertex',

\t/**
\t * Variable: AFTER_ADD_VERTEX
\t *
\t * Specifies the event name for afterAddVertex.
\t */
\tAFTER_ADD_VERTEX: 'afterAddVertex',

\t/**
\t * Variable: DONE
\t *
\t * Specifies the event name for done.
\t */
\tDONE: 'done',

\t/**
\t * Variable: EXECUTE
\t *
\t * Specifies the event name for execute.
\t */
\tEXECUTE: 'execute',

\t/**
\t * Variable: EXECUTED
\t *
\t * Specifies the event name for executed.
\t */
\tEXECUTED: 'executed',

\t/**
\t * Variable: BEGIN_UPDATE
\t *
\t * Specifies the event name for beginUpdate.
\t */
\tBEGIN_UPDATE: 'beginUpdate',

\t/**
\t * Variable: START_EDIT
\t *
\t * Specifies the event name for startEdit.
\t */
\tSTART_EDIT: 'startEdit',

\t/**
\t * Variable: END_UPDATE
\t *
\t * Specifies the event name for endUpdate.
\t */
\tEND_UPDATE: 'endUpdate',

\t/**
\t * Variable: END_EDIT
\t *
\t * Specifies the event name for endEdit.
\t */
\tEND_EDIT: 'endEdit',

\t/**
\t * Variable: BEFORE_UNDO
\t *
\t * Specifies the event name for beforeUndo.
\t */
\tBEFORE_UNDO: 'beforeUndo',

\t/**
\t * Variable: UNDO
\t *
\t * Specifies the event name for undo.
\t */
\tUNDO: 'undo',

\t/**
\t * Variable: REDO
\t *
\t * Specifies the event name for redo.
\t */
\tREDO: 'redo',

\t/**
\t * Variable: CHANGE
\t *
\t * Specifies the event name for change.
\t */
\tCHANGE: 'change',

\t/**
\t * Variable: NOTIFY
\t *
\t * Specifies the event name for notify.
\t */
\tNOTIFY: 'notify',

\t/**
\t * Variable: LAYOUT_CELLS
\t *
\t * Specifies the event name for layoutCells.
\t */
\tLAYOUT_CELLS: 'layoutCells',

\t/**
\t * Variable: CLICK
\t *
\t * Specifies the event name for click.
\t */
\tCLICK: 'click',

\t/**
\t * Variable: SCALE
\t *
\t * Specifies the event name for scale.
\t */
\tSCALE: 'scale',

\t/**
\t * Variable: TRANSLATE
\t *
\t * Specifies the event name for translate.
\t */
\tTRANSLATE: 'translate',

\t/**
\t * Variable: SCALE_AND_TRANSLATE
\t *
\t * Specifies the event name for scaleAndTranslate.
\t */
\tSCALE_AND_TRANSLATE: 'scaleAndTranslate',

\t/**
\t * Variable: UP
\t *
\t * Specifies the event name for up.
\t */
\tUP: 'up',

\t/**
\t * Variable: DOWN
\t *
\t * Specifies the event name for down.
\t */
\tDOWN: 'down',

\t/**
\t * Variable: ADD
\t *
\t * Specifies the event name for add.
\t */
\tADD: 'add',

\t/**
\t * Variable: REMOVE
\t *
\t * Specifies the event name for remove.
\t */
\tREMOVE: 'remove',
\t
\t/**
\t * Variable: CLEAR
\t *
\t * Specifies the event name for clear.
\t */
\tCLEAR: 'clear',

\t/**
\t * Variable: ADD_CELLS
\t *
\t * Specifies the event name for addCells.
\t */
\tADD_CELLS: 'addCells',

\t/**
\t * Variable: CELLS_ADDED
\t *
\t * Specifies the event name for cellsAdded.
\t */
\tCELLS_ADDED: 'cellsAdded',

\t/**
\t * Variable: MOVE_CELLS
\t *
\t * Specifies the event name for moveCells.
\t */
\tMOVE_CELLS: 'moveCells',

\t/**
\t * Variable: CELLS_MOVED
\t *
\t * Specifies the event name for cellsMoved.
\t */
\tCELLS_MOVED: 'cellsMoved',

\t/**
\t * Variable: RESIZE_CELLS
\t *
\t * Specifies the event name for resizeCells.
\t */
\tRESIZE_CELLS: 'resizeCells',

\t/**
\t * Variable: CELLS_RESIZED
\t *
\t * Specifies the event name for cellsResized.
\t */
\tCELLS_RESIZED: 'cellsResized',

\t/**
\t * Variable: TOGGLE_CELLS
\t *
\t * Specifies the event name for toggleCells.
\t */
\tTOGGLE_CELLS: 'toggleCells',

\t/**
\t * Variable: CELLS_TOGGLED
\t *
\t * Specifies the event name for cellsToggled.
\t */
\tCELLS_TOGGLED: 'cellsToggled',

\t/**
\t * Variable: ORDER_CELLS
\t *
\t * Specifies the event name for orderCells.
\t */
\tORDER_CELLS: 'orderCells',

\t/**
\t * Variable: CELLS_ORDERED
\t *
\t * Specifies the event name for cellsOrdered.
\t */
\tCELLS_ORDERED: 'cellsOrdered',

\t/**
\t * Variable: REMOVE_CELLS
\t *
\t * Specifies the event name for removeCells.
\t */
\tREMOVE_CELLS: 'removeCells',

\t/**
\t * Variable: CELLS_REMOVED
\t *
\t * Specifies the event name for cellsRemoved.
\t */
\tCELLS_REMOVED: 'cellsRemoved',

\t/**
\t * Variable: GROUP_CELLS
\t *
\t * Specifies the event name for groupCells.
\t */
\tGROUP_CELLS: 'groupCells',

\t/**
\t * Variable: UNGROUP_CELLS
\t *
\t * Specifies the event name for ungroupCells.
\t */
\tUNGROUP_CELLS: 'ungroupCells',

\t/**
\t * Variable: REMOVE_CELLS_FROM_PARENT
\t *
\t * Specifies the event name for removeCellsFromParent.
\t */
\tREMOVE_CELLS_FROM_PARENT: 'removeCellsFromParent',

\t/**
\t * Variable: FOLD_CELLS
\t *
\t * Specifies the event name for foldCells.
\t */
\tFOLD_CELLS: 'foldCells',

\t/**
\t * Variable: CELLS_FOLDED
\t *
\t * Specifies the event name for cellsFolded.
\t */
\tCELLS_FOLDED: 'cellsFolded',

\t/**
\t * Variable: ALIGN_CELLS
\t *
\t * Specifies the event name for alignCells.
\t */
\tALIGN_CELLS: 'alignCells',

\t/**
\t * Variable: LABEL_CHANGED
\t *
\t * Specifies the event name for labelChanged.
\t */
\tLABEL_CHANGED: 'labelChanged',

\t/**
\t * Variable: CONNECT_CELL
\t *
\t * Specifies the event name for connectCell.
\t */
\tCONNECT_CELL: 'connectCell',

\t/**
\t * Variable: CELL_CONNECTED
\t *
\t * Specifies the event name for cellConnected.
\t */
\tCELL_CONNECTED: 'cellConnected',

\t/**
\t * Variable: SPLIT_EDGE
\t *
\t * Specifies the event name for splitEdge.
\t */
\tSPLIT_EDGE: 'splitEdge',

\t/**
\t * Variable: FLIP_EDGE
\t *
\t * Specifies the event name for flipEdge.
\t */
\tFLIP_EDGE: 'flipEdge',

\t/**
\t * Variable: START_EDITING
\t *
\t * Specifies the event name for startEditing.
\t */
\tSTART_EDITING: 'startEditing',

\t/**
\t * Variable: EDITING_STARTED
\t *
\t * Specifies the event name for editingStarted.
\t */
\tEDITING_STARTED: 'editingStarted',

\t/**
\t * Variable: EDITING_STOPPED
\t *
\t * Specifies the event name for editingStopped.
\t */
\tEDITING_STOPPED: 'editingStopped',

\t/**
\t * Variable: ADD_OVERLAY
\t *
\t * Specifies the event name for addOverlay.
\t */
\tADD_OVERLAY: 'addOverlay',

\t/**
\t * Variable: REMOVE_OVERLAY
\t *
\t * Specifies the event name for removeOverlay.
\t */
\tREMOVE_OVERLAY: 'removeOverlay',

\t/**
\t * Variable: UPDATE_CELL_SIZE
\t *
\t * Specifies the event name for updateCellSize.
\t */
\tUPDATE_CELL_SIZE: 'updateCellSize',

\t/**
\t * Variable: ESCAPE
\t *
\t * Specifies the event name for escape.
\t */
\tESCAPE: 'escape',

\t/**
\t * Variable: DOUBLE_CLICK
\t *
\t * Specifies the event name for doubleClick.
\t */
\tDOUBLE_CLICK: 'doubleClick',

\t/**
\t * Variable: START
\t *
\t * Specifies the event name for start.
\t */
\tSTART: 'start',

\t/**
\t * Variable: RESET
\t *
\t * Specifies the event name for reset.
\t */
\tRESET: 'reset',

\t/**
\t * Variable: PINCH_THRESHOLD
\t *
\t * Threshold for pinch gestures to fire a mouse wheel event.
\t * Default value is 10.
\t */
\tPINCH_THRESHOLD: 10

};
/**
 * Copyright (c) 2006-2020, JGraph Ltd
 * Copyright (c) 2006-2020, draw.io AG
 */
/**
 * Class: mxXmlRequest
 * 
 * XML HTTP request wrapper. See also: <mxUtils.get>, <mxUtils.post> and
 * <mxUtils.load>. This class provides a cross-browser abstraction for Ajax
 * requests.
 * 
 * Encoding:
 * 
 * For encoding parameter values, the built-in encodeURIComponent JavaScript
 * method must be used. For automatic encoding of post data in <mxEditor> the
 * <mxEditor.escapePostData> switch can be set to true (default). The encoding
 * will be carried out using the conte type of the page. That is, the page
 * containting the editor should contain a meta tag in the header, eg.
 * <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">
 * 
 * Example:
 * 
 * (code)
 * var onload = function(req)
 * {
 *   mxUtils.alert(req.getDocumentElement());
 * }
 * 
 * var onerror = function(req)
 * {
 *   mxUtils.alert('Error');
 * }
 * new mxXmlRequest(url, 'key=value').send(onload, onerror);
 * (end)
 * 
 * Sends an asynchronous POST request to the specified URL.
 * 
 * Example:
 * 
 * (code)
 * var req = new mxXmlRequest(url, 'key=value', 'POST', false);
 * req.send();
 * mxUtils.alert(req.getDocumentElement());
 * (end)
 * 
 * Sends a synchronous POST request to the specified URL.
 * 
 * Example:
 * 
 * (code)
 * var encoder = new mxCodec();
 * var result = encoder.encode(graph.getModel());
 * var xml = encodeURIComponent(mxUtils.getXml(result));
 * new mxXmlRequest(url, 'xml='+xml).send();
 * (end)
 * 
 * Sends an encoded graph model to the specified URL using xml as the
 * parameter name. The parameter can then be retrieved in C# as follows:
 * 
 * (code)
 * string xml = HttpUtility.UrlDecode(context.Request.Params[\"xml\"]);
 * (end)
 * 
 * Or in Java as follows:
 * 
 * (code)
 * String xml = URLDecoder.decode(request.getParameter(\"xml\"), \"UTF-8\").replace(\"\\n\", \"&#xa;\");
 * (end)
 *
 * Note that the linefeeds should only be replaced if the XML is
 * processed in Java, for example when creating an image.
 * 
 * Constructor: mxXmlRequest
 * 
 * Constructs an XML HTTP request.
 * 
 * Parameters:
 * 
 * url - Target URL of the request.
 * params - Form encoded parameters to send with a POST request.
 * method - String that specifies the request method. Possible values are
 * POST and GET. Default is POST.
 * async - Boolean specifying if an asynchronous request should be used.
 * Default is true.
 * username - String specifying the username to be used for the request.
 * password - String specifying the password to be used for the request.
 */
function mxXmlRequest(url, params, method, async, username, password)
{
\tthis.url = url;
\tthis.params = params;
\tthis.method = method || 'POST';
\tthis.async = (async != null) ? async : true;
\tthis.username = username;
\tthis.password = password;
};

/**
 * Variable: url
 * 
 * Holds the target URL of the request.
 */
mxXmlRequest.prototype.url = null;

/**
 * Variable: params
 * 
 * Holds the form encoded data for the POST request.
 */
mxXmlRequest.prototype.params = null;

/**
 * Variable: method
 * 
 * Specifies the request method. Possible values are POST and GET. Default
 * is POST.
 */
mxXmlRequest.prototype.method = null;

/**
 * Variable: async
 * 
 * Boolean indicating if the request is asynchronous.
 */
mxXmlRequest.prototype.async = null;

/**
 * Variable: binary
 * 
 * Boolean indicating if the request is binary. This option is ignored in IE.
 * In all other browsers the requested mime type is set to
 * text/plain; charset=x-user-defined. Default is false.
 */
mxXmlRequest.prototype.binary = false;

/**
 * Variable: withCredentials
 * 
 * Specifies if withCredentials should be used in HTML5-compliant browsers. Default is
 * false.
 */
mxXmlRequest.prototype.withCredentials = false;

/**
 * Variable: username
 * 
 * Specifies the username to be used for authentication.
 */
mxXmlRequest.prototype.username = null;

/**
 * Variable: password
 * 
 * Specifies the password to be used for authentication.
 */
mxXmlRequest.prototype.password = null;

/**
 * Variable: request
 * 
 * Holds the inner, browser-specific request object.
 */
mxXmlRequest.prototype.request = null;

/**
 * Variable: decodeSimulateValues
 * 
 * Specifies if request values should be decoded as URIs before setting the
 * textarea value in <simulate>. Defaults to false for backwards compatibility,
 * to avoid another decode on the server this should be set to true.
 */
mxXmlRequest.prototype.decodeSimulateValues = false;

/**
 * Function: isBinary
 * 
 * Returns <binary>.
 */
mxXmlRequest.prototype.isBinary = function()
{
\treturn this.binary;
};

/**
 * Function: setBinary
 * 
 * Sets <binary>.
 */
mxXmlRequest.prototype.setBinary = function(value)
{
\tthis.binary = value;
};

/**
 * Function: getText
 * 
 * Returns the response as a string.
 */
mxXmlRequest.prototype.getText = function()
{
\treturn this.request.responseText;
};

/**
 * Function: isReady
 * 
 * Returns true if the response is ready.
 */
mxXmlRequest.prototype.isReady = function()
{
\treturn this.request.readyState == 4;
};

/**
 * Function: getDocumentElement
 * 
 * Returns the document element of the response XML document.
 */
mxXmlRequest.prototype.getDocumentElement = function()
{
\tvar doc = this.getXml();
\t
\tif (doc != null)
\t{
\t\treturn doc.documentElement;
\t}
\t
\treturn null;
};

/**
 * Function: getXml
 * 
 * Returns the response as an XML document. Use <getDocumentElement> to get
 * the document element of the XML document.
 */
mxXmlRequest.prototype.getXml = function()
{
\tvar xml = this.request.responseXML;
\t
\t// Handles missing response headers in IE, the first condition handles
\t// the case where responseXML is there, but using its nodes leads to
\t// type errors in the mxCellCodec when putting the nodes into a new
\t// document. This happens in IE9 standards mode and with XML user
\t// objects only, as they are used directly as values in cells.
\tif (document.documentMode >= 9 || xml == null || xml.documentElement == null)
\t{
\t\txml = mxUtils.parseXml(this.request.responseText);
\t}
\t
\treturn xml;
};

/**
 * Function: getStatus
 * 
 * Returns the status as a number, eg. 404 for \"Not found\" or 200 for \"OK\".
 * Note: The NS_ERROR_NOT_AVAILABLE for invalid responses cannot be cought.
 */
mxXmlRequest.prototype.getStatus = function()
{
\treturn (this.request != null) ? this.request.status : null;
};

/**
 * Function: create
 * 
 * Creates and returns the inner <request> object.
 */
mxXmlRequest.prototype.create = function()
{
\tif (window.XMLHttpRequest)
\t{
\t\treturn function()
\t\t{
\t\t\tvar req = new XMLHttpRequest();
\t\t\t
\t\t\t// TODO: Check for overrideMimeType required here?
\t\t\tif (this.isBinary() && req.overrideMimeType)
\t\t\t{
\t\t\t\treq.overrideMimeType('text/plain; charset=x-user-defined');
\t\t\t}

\t\t\treturn req;
\t\t};
\t}
\telse if (typeof(ActiveXObject) != 'undefined')
\t{
\t\treturn function()
\t\t{
\t\t\t// TODO: Implement binary option
\t\t\treturn new ActiveXObject('Microsoft.XMLHTTP');
\t\t};
\t}
}();

/**
 * Function: send
 * 
 * Send the <request> to the target URL using the specified functions to
 * process the response asychronously.
 * 
 * Note: Due to technical limitations, onerror is currently ignored.
 * 
 * Parameters:
 * 
 * onload - Function to be invoked if a successful response was received.
 * onerror - Function to be called on any error. Unused in this implementation, intended for overriden function.
 * timeout - Optional timeout in ms before calling ontimeout.
 * ontimeout - Optional function to execute on timeout.
 */
mxXmlRequest.prototype.send = function(onload, onerror, timeout, ontimeout)
{
\tthis.request = this.create();
\t
\tif (this.request != null)
\t{
\t\tif (onload != null)
\t\t{
\t\t\tthis.request.onreadystatechange = mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tif (this.isReady())
\t\t\t\t{
\t\t\t\t\tonload(this);
\t\t\t\t\tthis.request.onreadystatechange = null;
\t\t\t\t}
\t\t\t});
\t\t}

\t\tthis.request.open(this.method, this.url, this.async,
\t\t\tthis.username, this.password);
\t\tthis.setRequestHeaders(this.request, this.params);
\t\t
\t\tif (window.XMLHttpRequest && this.withCredentials)
\t\t{
\t\t\tthis.request.withCredentials = 'true';
\t\t}
\t\t
\t\tif (!mxClient.IS_QUIRKS && (document.documentMode == null || document.documentMode > 9) &&
\t\t\twindow.XMLHttpRequest && timeout != null && ontimeout != null)
\t\t{
\t\t\tthis.request.timeout = timeout;
\t\t\tthis.request.ontimeout = ontimeout;
\t\t}
\t\t\t\t
\t\tthis.request.send(this.params);
\t}
};

/**
 * Function: setRequestHeaders
 * 
 * Sets the headers for the given request and parameters. This sets the
 * content-type to application/x-www-form-urlencoded if any params exist.
 * 
 * Example:
 * 
 * (code)
 * request.setRequestHeaders = function(request, params)
 * {
 *   if (params != null)
 *   {
 *     request.setRequestHeader('Content-Type',
 *             'multipart/form-data');
 *     request.setRequestHeader('Content-Length',
 *             params.length);
 *   }
 * };
 * (end)
 * 
 * Use the code above before calling <send> if you require a
 * multipart/form-data request.   
 */
mxXmlRequest.prototype.setRequestHeaders = function(request, params)
{
\tif (params != null)
\t{
\t\trequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
\t}
};

/**
 * Function: simulate
 * 
 * Creates and posts a request to the given target URL using a dynamically
 * created form inside the given document.
 * 
 * Parameters:
 * 
 * docs - Document that contains the form element.
 * target - Target to send the form result to.
 */
mxXmlRequest.prototype.simulate = function(doc, target)
{
\tdoc = doc || document;
\tvar old = null;

\tif (doc == document)
\t{
\t\told = window.onbeforeunload;\t\t
\t\twindow.onbeforeunload = null;
\t}
\t\t\t
\tvar form = doc.createElement('form');
\tform.setAttribute('method', this.method);
\tform.setAttribute('action', this.url);

\tif (target != null)
\t{
\t\tform.setAttribute('target', target);
\t}

\tform.style.display = 'none';
\tform.style.visibility = 'hidden';
\t
\tvar pars = (this.params.indexOf('&') > 0) ?
\t\tthis.params.split('&') :
\t\tthis.params.split();

\t// Adds the parameters as textareas to the form
\tfor (var i=0; i<pars.length; i++)
\t{
\t\tvar pos = pars[i].indexOf('=');
\t\t
\t\tif (pos > 0)
\t\t{
\t\t\tvar name = pars[i].substring(0, pos);
\t\t\tvar value = pars[i].substring(pos+1);
\t\t\t
\t\t\tif (this.decodeSimulateValues)
\t\t\t{
\t\t\t\tvalue = decodeURIComponent(value);
\t\t\t}
\t\t\t
\t\t\tvar textarea = doc.createElement('textarea');
\t\t\ttextarea.setAttribute('wrap', 'off');
\t\t\ttextarea.setAttribute('name', name);
\t\t\tmxUtils.write(textarea, value);
\t\t\tform.appendChild(textarea);
\t\t}
\t}
\t
\tdoc.body.appendChild(form);
\tform.submit();
\t
\tif (form.parentNode != null)
\t{
\t\tform.parentNode.removeChild(form);
\t}

\tif (old != null)
\t{\t\t
\t\twindow.onbeforeunload = old;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxClipboard =
{
\t/**
\t * Class: mxClipboard
\t * 
\t * Singleton that implements a clipboard for graph cells.
\t *
\t * Example:
\t * 
\t * (code)
\t * mxClipboard.copy(graph);
\t * mxClipboard.paste(graph2);
\t * (end)
\t *
\t * This copies the selection cells from the graph to the clipboard and
\t * pastes them into graph2.
\t * 
\t * For fine-grained control of the clipboard data the <mxGraph.canExportCell>
\t * and <mxGraph.canImportCell> functions can be overridden.
\t * 
\t * To restore previous parents for pasted cells, the implementation for
\t * <copy> and <paste> can be changed as follows.
\t * 
\t * (code)
\t * mxClipboard.copy = function(graph, cells)
\t * {
\t *   cells = cells || graph.getSelectionCells();
\t *   var result = graph.getExportableCells(cells);
\t *   
\t *   mxClipboard.parents = new Object();
\t *   
\t *   for (var i = 0; i < result.length; i++)
\t *   {
\t *     mxClipboard.parents[i] = graph.model.getParent(cells[i]);
\t *   }
\t *   
\t *   mxClipboard.insertCount = 1;
\t *   mxClipboard.setCells(graph.cloneCells(result));
\t *   
\t *   return result;
\t * };
\t * 
\t * mxClipboard.paste = function(graph)
\t * {
\t *   if (!mxClipboard.isEmpty())
\t *   {
\t *     var cells = graph.getImportableCells(mxClipboard.getCells());
\t *     var delta = mxClipboard.insertCount * mxClipboard.STEPSIZE;
\t *     var parent = graph.getDefaultParent();
\t *     
\t *     graph.model.beginUpdate();
\t *     try
\t *     {
\t *       for (var i = 0; i < cells.length; i++)
\t *       {
\t *         var tmp = (mxClipboard.parents != null && graph.model.contains(mxClipboard.parents[i])) ?
\t *              mxClipboard.parents[i] : parent;
\t *         cells[i] = graph.importCells([cells[i]], delta, delta, tmp)[0];
\t *       }
\t *     }
\t *     finally
\t *     {
\t *       graph.model.endUpdate();
\t *     }
\t *     
\t *     // Increments the counter and selects the inserted cells
\t *     mxClipboard.insertCount++;
\t *     graph.setSelectionCells(cells);
\t *   }
\t * };
\t * (end)
\t * 
\t * Variable: STEPSIZE
\t * 
\t * Defines the step size to offset the cells after each paste operation.
\t * Default is 10.
\t */
\tSTEPSIZE: 10,

\t/**
\t * Variable: insertCount
\t * 
\t * Counts the number of times the clipboard data has been inserted.
\t */
\tinsertCount: 1,

\t/**
\t * Variable: cells
\t * 
\t * Holds the array of <mxCells> currently in the clipboard.
\t */
\tcells: null,

\t/**
\t * Function: setCells
\t * 
\t * Sets the cells in the clipboard. Fires a <mxEvent.CHANGE> event.
\t */
\tsetCells: function(cells)
\t{
\t\tmxClipboard.cells = cells;
\t},

\t/**
\t * Function: getCells
\t * 
\t * Returns  the cells in the clipboard.
\t */
\tgetCells: function()
\t{
\t\treturn mxClipboard.cells;
\t},
\t
\t/**
\t * Function: isEmpty
\t * 
\t * Returns true if the clipboard currently has not data stored.
\t */
\tisEmpty: function()
\t{
\t\treturn mxClipboard.getCells() == null;
\t},
\t
\t/**
\t * Function: cut
\t * 
\t * Cuts the given array of <mxCells> from the specified graph.
\t * If cells is null then the selection cells of the graph will
\t * be used. Returns the cells that have been cut from the graph.
\t *
\t * Parameters:
\t * 
\t * graph - <mxGraph> that contains the cells to be cut.
\t * cells - Optional array of <mxCells> to be cut.
\t */
\tcut: function(graph, cells)
\t{
\t\tcells = mxClipboard.copy(graph, cells);
\t\tmxClipboard.insertCount = 0;
\t\tmxClipboard.removeCells(graph, cells);
\t\t
\t\treturn cells;
\t},

\t/**
\t * Function: removeCells
\t * 
\t * Hook to remove the given cells from the given graph after
\t * a cut operation.
\t *
\t * Parameters:
\t * 
\t * graph - <mxGraph> that contains the cells to be cut.
\t * cells - Array of <mxCells> to be cut.
\t */
\tremoveCells: function(graph, cells)
\t{
\t\tgraph.removeCells(cells);
\t},

\t/**
\t * Function: copy
\t * 
\t * Copies the given array of <mxCells> from the specified
\t * graph to <cells>. Returns the original array of cells that has
\t * been cloned. Descendants of cells in the array are ignored.
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> that contains the cells to be copied.
\t * cells - Optional array of <mxCells> to be copied.
\t */
\tcopy: function(graph, cells)
\t{
\t\tcells = cells || graph.getSelectionCells();
\t\tvar result = graph.getExportableCells(graph.model.getTopmostCells(cells));
\t\tmxClipboard.insertCount = 1;
\t\tmxClipboard.setCells(graph.cloneCells(result));

\t\treturn result;
\t},

\t/**
\t * Function: paste
\t * 
\t * Pastes the <cells> into the specified graph restoring
\t * the relation to <parents>, if possible. If the parents
\t * are no longer in the graph or invisible then the
\t * cells are added to the graph's default or into the
\t * swimlane under the cell's new location if one exists.
\t * The cells are added to the graph using <mxGraph.importCells>
\t * and returned.
\t * 
\t * Parameters:
\t * 
\t * graph - <mxGraph> to paste the <cells> into.
\t */
\tpaste: function(graph)
\t{
\t\tvar cells = null;
\t\t
\t\tif (!mxClipboard.isEmpty())
\t\t{
\t\t\tcells = graph.getImportableCells(mxClipboard.getCells());
\t\t\tvar delta = mxClipboard.insertCount * mxClipboard.STEPSIZE;
\t\t\tvar parent = graph.getDefaultParent();
\t\t\tcells = graph.importCells(cells, delta, delta, parent);
\t\t\t
\t\t\t// Increments the counter and selects the inserted cells
\t\t\tmxClipboard.insertCount++;
\t\t\tgraph.setSelectionCells(cells);
\t\t}
\t\t
\t\treturn cells;
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxWindow
 * 
 * Basic window inside a document.
 * 
 * Examples:
 * 
 * Creating a simple window.
 *
 * (code)
 * var tb = document.createElement('div');
 * var wnd = new mxWindow('Title', tb, 100, 100, 200, 200, true, true);
 * wnd.setVisible(true); 
 * (end)
 *
 * Creating a window that contains an iframe. 
 * 
 * (code)
 * var frame = document.createElement('iframe');
 * frame.setAttribute('width', '192px');
 * frame.setAttribute('height', '172px');
 * frame.setAttribute('src', 'http://www.example.com/');
 * frame.style.backgroundColor = 'white';
 * 
 * var w = document.body.clientWidth;
 * var h = (document.body.clientHeight || document.documentElement.clientHeight);
 * var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 200, 200);
 * wnd.setVisible(true);
 * (end)
 * 
 * To limit the movement of a window, eg. to keep it from being moved beyond
 * the top, left corner the following method can be overridden (recommended):
 * 
 * (code)
 * wnd.setLocation = function(x, y)
 * {
 *   x = Math.max(0, x);
 *   y = Math.max(0, y);
 *   mxWindow.prototype.setLocation.apply(this, arguments);
 * };
 * (end)
 * 
 * Or the following event handler can be used:
 * 
 * (code)
 * wnd.addListener(mxEvent.MOVE, function(e)
 * {
 *   wnd.setLocation(Math.max(0, wnd.getX()), Math.max(0, wnd.getY()));
 * });
 * (end)
 * 
 * To keep a window inside the current window:
 * 
 * (code)
 * mxEvent.addListener(window, 'resize', mxUtils.bind(this, function()
 * {
 *   var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
 *   var ih = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
 *   
 *   var x = this.window.getX();
 *   var y = this.window.getY();
 *   
 *   if (x + this.window.table.clientWidth > iw)
 *   {
 *     x = Math.max(0, iw - this.window.table.clientWidth);
 *   }
 *   
 *   if (y + this.window.table.clientHeight > ih)
 *   {
 *     y = Math.max(0, ih - this.window.table.clientHeight);
 *   }
 *   
 *   if (this.window.getX() != x || this.window.getY() != y)
 *   {
 *     this.window.setLocation(x, y);
 *   }
 * }));
 * (end)
 *
 * Event: mxEvent.MOVE_START
 *
 * Fires before the window is moved. The <code>event</code> property contains
 * the corresponding mouse event.
 *
 * Event: mxEvent.MOVE
 *
 * Fires while the window is being moved. The <code>event</code> property
 * contains the corresponding mouse event.
 *
 * Event: mxEvent.MOVE_END
 *
 * Fires after the window is moved. The <code>event</code> property contains
 * the corresponding mouse event.
 *
 * Event: mxEvent.RESIZE_START
 *
 * Fires before the window is resized. The <code>event</code> property contains
 * the corresponding mouse event.
 *
 * Event: mxEvent.RESIZE
 *
 * Fires while the window is being resized. The <code>event</code> property
 * contains the corresponding mouse event.
 *
 * Event: mxEvent.RESIZE_END
 *
 * Fires after the window is resized. The <code>event</code> property contains
 * the corresponding mouse event.
 *
 * Event: mxEvent.MAXIMIZE
 * 
 * Fires after the window is maximized. The <code>event</code> property
 * contains the corresponding mouse event.
 * 
 * Event: mxEvent.MINIMIZE
 * 
 * Fires after the window is minimized. The <code>event</code> property
 * contains the corresponding mouse event.
 * 
 * Event: mxEvent.NORMALIZE
 * 
 * Fires after the window is normalized, that is, it returned from
 * maximized or minimized state. The <code>event</code> property contains the
 * corresponding mouse event.
 *  
 * Event: mxEvent.ACTIVATE
 * 
 * Fires after a window is activated. The <code>previousWindow</code> property
 * contains the previous window. The event sender is the active window.
 * 
 * Event: mxEvent.SHOW
 * 
 * Fires after the window is shown. This event has no properties.
 * 
 * Event: mxEvent.HIDE
 * 
 * Fires after the window is hidden. This event has no properties.
 * 
 * Event: mxEvent.CLOSE
 * 
 * Fires before the window is closed. The <code>event</code> property contains
 * the corresponding mouse event.
 * 
 * Event: mxEvent.DESTROY
 * 
 * Fires before the window is destroyed. This event has no properties.
 * 
 * Constructor: mxWindow
 * 
 * Constructs a new window with the given dimension and title to display
 * the specified content. The window elements use the given style as a
 * prefix for the classnames of the respective window elements, namely,
 * the window title and window pane. The respective postfixes are appended
 * to the given stylename as follows:
 * 
 *   style - Base style for the window.
 *   style+Title - Style for the window title.
 *   style+Pane - Style for the window pane.
 * 
 * The default value for style is mxWindow, resulting in the following
 * classnames for the window elements: mxWindow, mxWindowTitle and
 * mxWindowPane.
 * 
 * If replaceNode is given then the window replaces the given DOM node in
 * the document.
 * 
 * Parameters:
 * 
 * title - String that represents the title of the new window.
 * content - DOM node that is used as the window content.
 * x - X-coordinate of the window location.
 * y - Y-coordinate of the window location.
 * width - Width of the window.
 * height - Optional height of the window. Default is to match the height
 * of the content at the specified width.
 * minimizable - Optional boolean indicating if the window is minimizable.
 * Default is true.
 * movable - Optional boolean indicating if the window is movable. Default
 * is true.
 * replaceNode - Optional DOM node that the window should replace.
 * style - Optional base classname for the window elements. Default is
 * mxWindow.
 */
function mxWindow(title, content, x, y, width, height, minimizable, movable, replaceNode, style)
{
\tif (content != null)
\t{
\t\tminimizable = (minimizable != null) ? minimizable : true;
\t\tthis.content = content;
\t\tthis.init(x, y, width, height, style);
\t\t
\t\tthis.installMaximizeHandler();
\t\tthis.installMinimizeHandler();
\t\tthis.installCloseHandler();
\t\tthis.setMinimizable(minimizable);
\t\tthis.setTitle(title);
\t\t
\t\tif (movable == null || movable)
\t\t{
\t\t\tthis.installMoveHandler();
\t\t}

\t\tif (replaceNode != null && replaceNode.parentNode != null)
\t\t{
\t\t\treplaceNode.parentNode.replaceChild(this.div, replaceNode);
\t\t}
\t\telse
\t\t{
\t\t\tdocument.body.appendChild(this.div);
\t\t}
\t}
};

/**
 * Extends mxEventSource.
 */
mxWindow.prototype = new mxEventSource();
mxWindow.prototype.constructor = mxWindow;

/**
 * Variable: closeImage
 * 
 * URL of the image to be used for the close icon in the titlebar.
 */
mxWindow.prototype.closeImage = mxClient.imageBasePath + '/close.gif';

/**
 * Variable: minimizeImage
 * 
 * URL of the image to be used for the minimize icon in the titlebar.
 */
mxWindow.prototype.minimizeImage = mxClient.imageBasePath + '/minimize.gif';
\t
/**
 * Variable: normalizeImage
 * 
 * URL of the image to be used for the normalize icon in the titlebar.
 */
mxWindow.prototype.normalizeImage = mxClient.imageBasePath + '/normalize.gif';
\t
/**
 * Variable: maximizeImage
 * 
 * URL of the image to be used for the maximize icon in the titlebar.
 */
mxWindow.prototype.maximizeImage = mxClient.imageBasePath + '/maximize.gif';

/**
 * Variable: resizeImage
 * 
 * URL of the image to be used for the resize icon.
 */
mxWindow.prototype.resizeImage = mxClient.imageBasePath + '/resize.gif';

/**
 * Variable: visible
 * 
 * Boolean flag that represents the visible state of the window.
 */
mxWindow.prototype.visible = false;

/**
 * Variable: minimumSize
 * 
 * <mxRectangle> that specifies the minimum width and height of the window.
 * Default is (50, 40).
 */
mxWindow.prototype.minimumSize = new mxRectangle(0, 0, 50, 40);

/**
 * Variable: destroyOnClose
 * 
 * Specifies if the window should be destroyed when it is closed. If this
 * is false then the window is hidden using <setVisible>. Default is true.
 */
mxWindow.prototype.destroyOnClose = true;

/**
 * Variable: contentHeightCorrection
 * 
 * Defines the correction factor for computing the height of the contentWrapper.
 * Default is 6 for IE 7/8 standards mode and 2 for all other browsers and modes.
 */
mxWindow.prototype.contentHeightCorrection = (document.documentMode == 8 || document.documentMode == 7) ? 6 : 2;

/**
 * Variable: title
 * 
 * Reference to the DOM node (TD) that contains the title.
 */
mxWindow.prototype.title = null;

/**
 * Variable: content
 * 
 * Reference to the DOM node that represents the window content.
 */
mxWindow.prototype.content = null;

/**
 * Function: init
 * 
 * Initializes the DOM tree that represents the window.
 */
mxWindow.prototype.init = function(x, y, width, height, style)
{
\tstyle = (style != null) ? style : 'mxWindow';
\t
\tthis.div = document.createElement('div');
\tthis.div.className = style;

\tthis.div.style.left = x + 'px';
\tthis.div.style.top = y + 'px';
\tthis.table = document.createElement('table');
\tthis.table.className = style;

\t// Disables built-in pan and zoom in IE10 and later
\tif (mxClient.IS_POINTER)
\t{
\t\tthis.div.style.touchAction = 'none';
\t}
\t
\t// Workaround for table size problems in FF
\tif (width != null)
\t{
\t\tif (!mxClient.IS_QUIRKS)
\t\t{
\t\t\tthis.div.style.width = width + 'px'; 
\t\t}
\t\t
\t\tthis.table.style.width = width + 'px';
\t} 
\t
\tif (height != null)
\t{
\t\tif (!mxClient.IS_QUIRKS)
\t\t{
\t\t\tthis.div.style.height = height + 'px';
\t\t}
\t\t
\t\tthis.table.style.height = height + 'px';
\t}\t\t
\t
\t// Creates title row
\tvar tbody = document.createElement('tbody');
\tvar tr = document.createElement('tr');
\t
\tthis.title = document.createElement('td');
\tthis.title.className = style + 'Title';
\t
\tthis.buttons = document.createElement('div');
\tthis.buttons.style.position = 'absolute';
\tthis.buttons.style.display = 'inline-block';
\tthis.buttons.style.right = '4px';
\tthis.buttons.style.top = '5px';
\tthis.title.appendChild(this.buttons);
\t
\ttr.appendChild(this.title);
\ttbody.appendChild(tr);
\t
\t// Creates content row and table cell
\ttr = document.createElement('tr');
\tthis.td = document.createElement('td');
\tthis.td.className = style + 'Pane';
\t
\tif (document.documentMode == 7)
\t{
\t\tthis.td.style.height = '100%';
\t}

\tthis.contentWrapper = document.createElement('div');
\tthis.contentWrapper.className = style + 'Pane';
\tthis.contentWrapper.style.width = '100%';
\tthis.contentWrapper.appendChild(this.content);

\t// Workaround for div around div restricts height
\t// of inner div if outerdiv has hidden overflow
\tif (mxClient.IS_QUIRKS || this.content.nodeName.toUpperCase() != 'DIV')
\t{
\t\tthis.contentWrapper.style.height = '100%';
\t}

\t// Puts all content into the DOM
\tthis.td.appendChild(this.contentWrapper);
\ttr.appendChild(this.td);
\ttbody.appendChild(tr);
\tthis.table.appendChild(tbody);
\tthis.div.appendChild(this.table);
\t
\t// Puts the window on top of other windows when clicked
\tvar activator = mxUtils.bind(this, function(evt)
\t{
\t\tthis.activate();
\t});
\t
\tmxEvent.addGestureListeners(this.title, activator);
\tmxEvent.addGestureListeners(this.table, activator);

\tthis.hide();
};

/**
 * Function: setTitle
 * 
 * Sets the window title to the given string. HTML markup inside the title
 * will be escaped.
 */
mxWindow.prototype.setTitle = function(title)
{
\t// Removes all text content nodes (normally just one)
\tvar child = this.title.firstChild;
\t
\twhile (child != null)
\t{
\t\tvar next = child.nextSibling;
\t\t
\t\tif (child.nodeType == mxConstants.NODETYPE_TEXT)
\t\t{
\t\t\tchild.parentNode.removeChild(child);
\t\t}
\t\t
\t\tchild = next;
\t}
\t
\tmxUtils.write(this.title, title || '');
\tthis.title.appendChild(this.buttons);
};

/**
 * Function: setScrollable
 * 
 * Sets if the window contents should be scrollable.
 */
mxWindow.prototype.setScrollable = function(scrollable)
{
\t// Workaround for hang in Presto 2.5.22 (Opera 10.5)
\tif (navigator.userAgent == null ||
\t\tnavigator.userAgent.indexOf('Presto/2.5') < 0)
\t{
\t\tif (scrollable)
\t\t{
\t\t\tthis.contentWrapper.style.overflow = 'auto';
\t\t}
\t\telse
\t\t{
\t\t\tthis.contentWrapper.style.overflow = 'hidden';
\t\t}
\t}
};

/**
 * Function: activate
 * 
 * Puts the window on top of all other windows.
 */
mxWindow.prototype.activate = function()
{
\tif (mxWindow.activeWindow != this)
\t{
\t\tvar style = mxUtils.getCurrentStyle(this.getElement());
\t\tvar index = (style != null) ? style.zIndex : 3;

\t\tif (mxWindow.activeWindow)
\t\t{
\t\t\tvar elt = mxWindow.activeWindow.getElement();
\t\t\t
\t\t\tif (elt != null && elt.style != null)
\t\t\t{
\t\t\t\telt.style.zIndex = index;
\t\t\t}
\t\t}
\t\t
\t\tvar previousWindow = mxWindow.activeWindow;
\t\tthis.getElement().style.zIndex = parseInt(index) + 1;
\t\tmxWindow.activeWindow = this;
\t\t
\t\tthis.fireEvent(new mxEventObject(mxEvent.ACTIVATE, 'previousWindow', previousWindow));
\t}
};

/**
 * Function: getElement
 * 
 * Returuns the outermost DOM node that makes up the window.
 */
mxWindow.prototype.getElement = function()
{
\treturn this.div;
};

/**
 * Function: fit
 * 
 * Makes sure the window is inside the client area of the window.
 */
mxWindow.prototype.fit = function()
{
\tmxUtils.fit(this.div);
};

/**
 * Function: isResizable
 * 
 * Returns true if the window is resizable.
 */
mxWindow.prototype.isResizable = function()
{
\tif (this.resize != null)
\t{
\t\treturn this.resize.style.display != 'none';
\t}
\t
\treturn false;
};

/**
 * Function: setResizable
 * 
 * Sets if the window should be resizable. To avoid interference with some
 * built-in features of IE10 and later, the use of the following code is
 * recommended if there are resizable <mxWindow>s in the page:
 * 
 * (code)
 * if (mxClient.IS_POINTER)
 * {
 *   document.body.style.msTouchAction = 'none';
 * }
 * (end)
 */
mxWindow.prototype.setResizable = function(resizable)
{
\tif (resizable)
\t{
\t\tif (this.resize == null)
\t\t{
\t\t\tthis.resize = document.createElement('img');
\t\t\tthis.resize.style.position = 'absolute';
\t\t\tthis.resize.style.bottom = '2px';
\t\t\tthis.resize.style.right = '2px';

\t\t\tthis.resize.setAttribute('src', this.resizeImage);
\t\t\tthis.resize.style.cursor = 'nw-resize';
\t\t\t
\t\t\tvar startX = null;
\t\t\tvar startY = null;
\t\t\tvar width = null;
\t\t\tvar height = null;
\t\t\t
\t\t\tvar start = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\t// LATER: pointerdown starting on border of resize does start
\t\t\t\t// the drag operation but does not fire consecutive events via
\t\t\t\t// one of the listeners below (does pan instead).
\t\t\t\t// Workaround: document.body.style.msTouchAction = 'none'
\t\t\t\tthis.activate();
\t\t\t\tstartX = mxEvent.getClientX(evt);
\t\t\t\tstartY = mxEvent.getClientY(evt);
\t\t\t\twidth = this.div.offsetWidth;
\t\t\t\theight = this.div.offsetHeight;
\t\t\t\t
\t\t\t\tmxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.RESIZE_START, 'event', evt));
\t\t\t\tmxEvent.consume(evt);
\t\t\t});

\t\t\t// Adds a temporary pair of listeners to intercept
\t\t\t// the gesture event in the document
\t\t\tvar dragHandler = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (startX != null && startY != null)
\t\t\t\t{
\t\t\t\t\tvar dx = mxEvent.getClientX(evt) - startX;
\t\t\t\t\tvar dy = mxEvent.getClientY(evt) - startY;
\t
\t\t\t\t\tthis.setSize(width + dx, height + dy);
\t
\t\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.RESIZE, 'event', evt));
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tvar dropHandler = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (startX != null && startY != null)
\t\t\t\t{
\t\t\t\t\tstartX = null;
\t\t\t\t\tstartY = null;
\t\t\t\t\tmxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
\t\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.RESIZE_END, 'event', evt));
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tmxEvent.addGestureListeners(this.resize, start, dragHandler, dropHandler);
\t\t\tthis.div.appendChild(this.resize);
\t\t}
\t\telse 
\t\t{
\t\t\tthis.resize.style.display = 'inline';
\t\t}
\t}
\telse if (this.resize != null)
\t{
\t\tthis.resize.style.display = 'none';
\t}
};
\t
/**
 * Function: setSize
 * 
 * Sets the size of the window.
 */
mxWindow.prototype.setSize = function(width, height)
{
\twidth = Math.max(this.minimumSize.width, width);
\theight = Math.max(this.minimumSize.height, height);

\t// Workaround for table size problems in FF
\tif (!mxClient.IS_QUIRKS)
\t{
\t\tthis.div.style.width =  width + 'px';
\t\tthis.div.style.height = height + 'px';
\t}
\t
\tthis.table.style.width =  width + 'px';
\tthis.table.style.height = height + 'px';

\tif (!mxClient.IS_QUIRKS)
\t{
\t\tthis.contentWrapper.style.height = (this.div.offsetHeight -
\t\t\tthis.title.offsetHeight - this.contentHeightCorrection) + 'px';
\t}
};
\t
/**
 * Function: setMinimizable
 * 
 * Sets if the window is minimizable.
 */
mxWindow.prototype.setMinimizable = function(minimizable)
{
\tthis.minimize.style.display = (minimizable) ? '' : 'none';
};

/**
 * Function: getMinimumSize
 * 
 * Returns an <mxRectangle> that specifies the size for the minimized window.
 * A width or height of 0 means keep the existing width or height. This
 * implementation returns the height of the window title and keeps the width.
 */
mxWindow.prototype.getMinimumSize = function()
{
\treturn new mxRectangle(0, 0, 0, this.title.offsetHeight);
};

/**
 * Function: installMinimizeHandler
 * 
 * Installs the event listeners required for minimizing the window.
 */
mxWindow.prototype.installMinimizeHandler = function()
{
\tthis.minimize = document.createElement('img');
\t
\tthis.minimize.setAttribute('src', this.minimizeImage);
\tthis.minimize.setAttribute('title', 'Minimize');
\tthis.minimize.style.cursor = 'pointer';
\tthis.minimize.style.marginLeft = '2px';
\tthis.minimize.style.display = 'none';
\t
\tthis.buttons.appendChild(this.minimize);
\t
\tvar minimized = false;
\tvar maxDisplay = null;
\tvar height = null;

\tvar funct = mxUtils.bind(this, function(evt)
\t{
\t\tthis.activate();
\t\t
\t\tif (!minimized)
\t\t{
\t\t\tminimized = true;
\t\t\t
\t\t\tthis.minimize.setAttribute('src', this.normalizeImage);
\t\t\tthis.minimize.setAttribute('title', 'Normalize');
\t\t\tthis.contentWrapper.style.display = 'none';
\t\t\tmaxDisplay = this.maximize.style.display;
\t\t\t
\t\t\tthis.maximize.style.display = 'none';
\t\t\theight = this.table.style.height;
\t\t\t
\t\t\tvar minSize = this.getMinimumSize();
\t\t\t
\t\t\tif (minSize.height > 0)
\t\t\t{
\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tthis.div.style.height = minSize.height + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.table.style.height = minSize.height + 'px';
\t\t\t}
\t\t\t
\t\t\tif (minSize.width > 0)
\t\t\t{
\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tthis.div.style.width = minSize.width + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.table.style.width = minSize.width + 'px';
\t\t\t}
\t\t\t
\t\t\tif (this.resize != null)
\t\t\t{
\t\t\t\tthis.resize.style.visibility = 'hidden';
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MINIMIZE, 'event', evt));
\t\t}
\t\telse
\t\t{
\t\t\tminimized = false;
\t\t\t
\t\t\tthis.minimize.setAttribute('src', this.minimizeImage);
\t\t\tthis.minimize.setAttribute('title', 'Minimize');
\t\t\tthis.contentWrapper.style.display = ''; // default
\t\t\tthis.maximize.style.display = maxDisplay;
\t\t\t
\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t{
\t\t\t\tthis.div.style.height = height;
\t\t\t}
\t\t\t
\t\t\tthis.table.style.height = height;

\t\t\tif (this.resize != null)
\t\t\t{
\t\t\t\tthis.resize.style.visibility = '';
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
\t\t}
\t\t
\t\tmxEvent.consume(evt);
\t});
\t
\tmxEvent.addGestureListeners(this.minimize, funct);
};
\t
/**
 * Function: setMaximizable
 * 
 * Sets if the window is maximizable.
 */
mxWindow.prototype.setMaximizable = function(maximizable)
{
\tthis.maximize.style.display = (maximizable) ? '' : 'none';
};

/**
 * Function: installMaximizeHandler
 * 
 * Installs the event listeners required for maximizing the window.
 */
mxWindow.prototype.installMaximizeHandler = function()
{
\tthis.maximize = document.createElement('img');
\t
\tthis.maximize.setAttribute('src', this.maximizeImage);
\tthis.maximize.setAttribute('title', 'Maximize');
\tthis.maximize.style.cursor = 'default';
\tthis.maximize.style.marginLeft = '2px';
\tthis.maximize.style.cursor = 'pointer';
\tthis.maximize.style.display = 'none';
\t
\tthis.buttons.appendChild(this.maximize);
\t
\tvar maximized = false;
\tvar x = null;
\tvar y = null;
\tvar height = null;
\tvar width = null;
\tvar minDisplay = null;

\tvar funct = mxUtils.bind(this, function(evt)
\t{
\t\tthis.activate();
\t\t
\t\tif (this.maximize.style.display != 'none')
\t\t{
\t\t\tif (!maximized)
\t\t\t{
\t\t\t\tmaximized = true;
\t\t\t\t
\t\t\t\tthis.maximize.setAttribute('src', this.normalizeImage);
\t\t\t\tthis.maximize.setAttribute('title', 'Normalize');
\t\t\t\tthis.contentWrapper.style.display = '';
\t\t\t\tminDisplay = this.minimize.style.display;
\t\t\t\tthis.minimize.style.display = 'none';
\t\t\t\t
\t\t\t\t// Saves window state
\t\t\t\tx = parseInt(this.div.style.left);
\t\t\t\ty = parseInt(this.div.style.top);
\t\t\t\theight = this.table.style.height;
\t\t\t\twidth = this.table.style.width;

\t\t\t\tthis.div.style.left = '0px';
\t\t\t\tthis.div.style.top = '0px';
\t\t\t\tvar docHeight = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight || 0);

\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tthis.div.style.width = (document.body.clientWidth - 2) + 'px';
\t\t\t\t\tthis.div.style.height = (docHeight - 2) + 'px';
\t\t\t\t}

\t\t\t\tthis.table.style.width = (document.body.clientWidth - 2) + 'px';
\t\t\t\tthis.table.style.height = (docHeight - 2) + 'px';
\t\t\t\t
\t\t\t\tif (this.resize != null)
\t\t\t\t{
\t\t\t\t\tthis.resize.style.visibility = 'hidden';
\t\t\t\t}

\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tvar style = mxUtils.getCurrentStyle(this.contentWrapper);
\t\t
\t\t\t\t\tif (style.overflow == 'auto' || this.resize != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.contentWrapper.style.height = (this.div.offsetHeight -
\t\t\t\t\t\t\tthis.title.offsetHeight - this.contentHeightCorrection) + 'px';
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MAXIMIZE, 'event', evt));
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tmaximized = false;
\t\t\t\t
\t\t\t\tthis.maximize.setAttribute('src', this.maximizeImage);
\t\t\t\tthis.maximize.setAttribute('title', 'Maximize');
\t\t\t\tthis.contentWrapper.style.display = '';
\t\t\t\tthis.minimize.style.display = minDisplay;

\t\t\t\t// Restores window state
\t\t\t\tthis.div.style.left = x+'px';
\t\t\t\tthis.div.style.top = y+'px';
\t\t\t\t
\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tthis.div.style.height = height;
\t\t\t\t\tthis.div.style.width = width;

\t\t\t\t\tvar style = mxUtils.getCurrentStyle(this.contentWrapper);
\t\t
\t\t\t\t\tif (style.overflow == 'auto' || this.resize != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.contentWrapper.style.height = (this.div.offsetHeight -
\t\t\t\t\t\t\tthis.title.offsetHeight - this.contentHeightCorrection) + 'px';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.table.style.height = height;
\t\t\t\tthis.table.style.width = width;

\t\t\t\tif (this.resize != null)
\t\t\t\t{
\t\t\t\t\tthis.resize.style.visibility = '';
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
\t\t\t}
\t\t\t
\t\t\tmxEvent.consume(evt);
\t\t}
\t});
\t
\tmxEvent.addGestureListeners(this.maximize, funct);
\tmxEvent.addListener(this.title, 'dblclick', funct);
};
\t
/**
 * Function: installMoveHandler
 * 
 * Installs the event listeners required for moving the window.
 */
mxWindow.prototype.installMoveHandler = function()
{
\tthis.title.style.cursor = 'move';
\t
\tmxEvent.addGestureListeners(this.title,
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tvar startX = mxEvent.getClientX(evt);
\t\t\tvar startY = mxEvent.getClientY(evt);
\t\t\tvar x = this.getX();
\t\t\tvar y = this.getY();
\t\t\t\t\t\t
\t\t\t// Adds a temporary pair of listeners to intercept
\t\t\t// the gesture event in the document
\t\t\tvar dragHandler = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tvar dx = mxEvent.getClientX(evt) - startX;
\t\t\t\tvar dy = mxEvent.getClientY(evt) - startY;
\t\t\t\tthis.setLocation(x + dx, y + dy);
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MOVE, 'event', evt));
\t\t\t\tmxEvent.consume(evt);
\t\t\t});
\t\t\t
\t\t\tvar dropHandler = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tmxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MOVE_END, 'event', evt));
\t\t\t\tmxEvent.consume(evt);
\t\t\t});
\t\t\t
\t\t\tmxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MOVE_START, 'event', evt));
\t\t\tmxEvent.consume(evt);
\t\t}));
\t
\t// Disables built-in pan and zoom in IE10 and later
\tif (mxClient.IS_POINTER)
\t{
\t\tthis.title.style.touchAction = 'none';
\t}
};

/**
 * Function: setLocation
 * 
 * Sets the upper, left corner of the window.
 */
 mxWindow.prototype.setLocation = function(x, y)
 {
\tthis.div.style.left = x + 'px';
\tthis.div.style.top = y + 'px';
 };

/**
 * Function: getX
 *
 * Returns the current position on the x-axis.
 */
mxWindow.prototype.getX = function()
{
\treturn parseInt(this.div.style.left);
};

/**
 * Function: getY
 *
 * Returns the current position on the y-axis.
 */
mxWindow.prototype.getY = function()
{
\treturn parseInt(this.div.style.top);
};

/**
 * Function: installCloseHandler
 *
 * Adds the <closeImage> as a new image node in <closeImg> and installs the
 * <close> event.
 */
mxWindow.prototype.installCloseHandler = function()
{
\tthis.closeImg = document.createElement('img');
\t
\tthis.closeImg.setAttribute('src', this.closeImage);
\tthis.closeImg.setAttribute('title', 'Close');
\tthis.closeImg.style.marginLeft = '2px';
\tthis.closeImg.style.cursor = 'pointer';
\tthis.closeImg.style.display = 'none';
\t
\tthis.buttons.appendChild(this.closeImg);

\tmxEvent.addGestureListeners(this.closeImg,
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CLOSE, 'event', evt));
\t\t\t
\t\t\tif (this.destroyOnClose)
\t\t\t{
\t\t\t\tthis.destroy();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.setVisible(false);
\t\t\t}
\t\t\t
\t\t\tmxEvent.consume(evt);
\t\t}));
};

/**
 * Function: setImage
 * 
 * Sets the image associated with the window.
 * 
 * Parameters:
 * 
 * image - URL of the image to be used.
 */
mxWindow.prototype.setImage = function(image)
{
\tthis.image = document.createElement('img');
\tthis.image.setAttribute('src', image);
\tthis.image.setAttribute('align', 'left');
\tthis.image.style.marginRight = '4px';
\tthis.image.style.marginLeft = '0px';
\tthis.image.style.marginTop = '-2px';
\t
\tthis.title.insertBefore(this.image, this.title.firstChild);
};

/**
 * Function: setClosable
 * 
 * Sets the image associated with the window.
 * 
 * Parameters:
 * 
 * closable - Boolean specifying if the window should be closable.
 */
mxWindow.prototype.setClosable = function(closable)
{
\tthis.closeImg.style.display = (closable) ? '' : 'none';
};

/**
 * Function: isVisible
 * 
 * Returns true if the window is visible.
 */
mxWindow.prototype.isVisible = function()
{
\tif (this.div != null)
\t{
\t\treturn this.div.style.display != 'none';
\t}
\t
\treturn false;
};

/**
 * Function: setVisible
 *
 * Shows or hides the window depending on the given flag.
 * 
 * Parameters:
 * 
 * visible - Boolean indicating if the window should be made visible.
 */
mxWindow.prototype.setVisible = function(visible)
{
\tif (this.div != null && this.isVisible() != visible)
\t{
\t\tif (visible)
\t\t{
\t\t\tthis.show();
\t\t}
\t\telse
\t\t{
\t\t\tthis.hide();
\t\t}
\t}
};

/**
 * Function: show
 *
 * Shows the window.
 */
mxWindow.prototype.show = function()
{
\tthis.div.style.display = '';
\tthis.activate();
\t
\tvar style = mxUtils.getCurrentStyle(this.contentWrapper);
\t
\tif (!mxClient.IS_QUIRKS && (style.overflow == 'auto' || this.resize != null) &&
\t\tthis.contentWrapper.style.display != 'none')
\t{
\t\tthis.contentWrapper.style.height = (this.div.offsetHeight -
\t\t\t\tthis.title.offsetHeight - this.contentHeightCorrection) + 'px';
\t}
\t
\tthis.fireEvent(new mxEventObject(mxEvent.SHOW));
};

/**
 * Function: hide
 *
 * Hides the window.
 */
mxWindow.prototype.hide = function()
{
\tthis.div.style.display = 'none';
\tthis.fireEvent(new mxEventObject(mxEvent.HIDE));
};

/**
 * Function: destroy
 *
 * Destroys the window and removes all associated resources. Fires a
 * <destroy> event prior to destroying the window.
 */
mxWindow.prototype.destroy = function()
{
\tthis.fireEvent(new mxEventObject(mxEvent.DESTROY));
\t
\tif (this.div != null)
\t{
\t\tmxEvent.release(this.div);
\t\tthis.div.parentNode.removeChild(this.div);
\t\tthis.div = null;
\t}
\t
\tthis.title = null;
\tthis.content = null;
\tthis.contentWrapper = null;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxForm
 * 
 * A simple class for creating HTML forms.
 * 
 * Constructor: mxForm
 * 
 * Creates a HTML table using the specified classname.
 */
function mxForm(className)
{
\tthis.table = document.createElement('table');
\tthis.table.className = className;
\tthis.body = document.createElement('tbody');
\t
\tthis.table.appendChild(this.body);
};

/**
 * Variable: table
 * 
 * Holds the DOM node that represents the table.
 */
mxForm.prototype.table = null;

/**
 * Variable: body
 * 
 * Holds the DOM node that represents the tbody (table body). New rows
 * can be added to this object using DOM API.
 */
mxForm.prototype.body = false;

/**
 * Function: getTable
 * 
 * Returns the table that contains this form.
 */
mxForm.prototype.getTable = function()
{
\treturn this.table;
};

/**
 * Function: addButtons
 * 
 * Helper method to add an OK and Cancel button using the respective
 * functions.
 */
mxForm.prototype.addButtons = function(okFunct, cancelFunct)
{
\tvar tr = document.createElement('tr');
\tvar td = document.createElement('td');
\ttr.appendChild(td);
\ttd = document.createElement('td');

\t// Adds the ok button
\tvar button = document.createElement('button');
\tmxUtils.write(button, mxResources.get('ok') || 'OK');
\ttd.appendChild(button);

\tmxEvent.addListener(button, 'click', function()
\t{
\t\tokFunct();
\t});
\t
\t// Adds the cancel button
\tbutton = document.createElement('button');
\tmxUtils.write(button, mxResources.get('cancel') || 'Cancel');
\ttd.appendChild(button);
\t
\tmxEvent.addListener(button, 'click', function()
\t{
\t\tcancelFunct();
\t});
\t
\ttr.appendChild(td);
\tthis.body.appendChild(tr);
};

/**
 * Function: addText
 * 
 * Adds an input for the given name, type and value and returns it.
 */
mxForm.prototype.addText = function(name, value, type)
{
\tvar input = document.createElement('input');
\t
\tinput.setAttribute('type', type || 'text');
\tinput.value = value;
\t
\treturn this.addField(name, input);
};

/**
 * Function: addCheckbox
 * 
 * Adds a checkbox for the given name and value and returns the textfield.
 */
mxForm.prototype.addCheckbox = function(name, value)
{
\tvar input = document.createElement('input');
\t
\tinput.setAttribute('type', 'checkbox');
\tthis.addField(name, input);

\t// IE can only change the checked value if the input is inside the DOM
\tif (value)
\t{
\t\tinput.checked = true;
\t}

\treturn input;
};

/**
 * Function: addTextarea
 * 
 * Adds a textarea for the given name and value and returns the textarea.
 */
mxForm.prototype.addTextarea = function(name, value, rows)
{
\tvar input = document.createElement('textarea');
\t
\tif (mxClient.IS_NS)
\t{
\t\trows--;
\t}
\t
\tinput.setAttribute('rows', rows || 2);
\tinput.value = value;
\t
\treturn this.addField(name, input);
};

/**
 * Function: addCombo
 * 
 * Adds a combo for the given name and returns the combo.
 */
mxForm.prototype.addCombo = function(name, isMultiSelect, size)
{
\tvar select = document.createElement('select');
\t
\tif (size != null)
\t{
\t\tselect.setAttribute('size', size);
\t}
\t
\tif (isMultiSelect)
\t{
\t\tselect.setAttribute('multiple', 'true');
\t}
\t
\treturn this.addField(name, select);
};

/**
 * Function: addOption
 * 
 * Adds an option for the given label to the specified combo.
 */
mxForm.prototype.addOption = function(combo, label, value, isSelected)
{
\tvar option = document.createElement('option');
\t
\tmxUtils.writeln(option, label);
\toption.setAttribute('value', value);
\t
\tif (isSelected)
\t{
\t\toption.setAttribute('selected', isSelected);
\t}
\t
\tcombo.appendChild(option);
};

/**
 * Function: addField
 * 
 * Adds a new row with the name and the input field in two columns and
 * returns the given input.
 */
mxForm.prototype.addField = function(name, input)
{
\tvar tr = document.createElement('tr');
\tvar td = document.createElement('td');
\tmxUtils.write(td, name);
\ttr.appendChild(td);
\t
\ttd = document.createElement('td');
\ttd.appendChild(input);
\ttr.appendChild(td);
\tthis.body.appendChild(tr);
\t
\treturn input;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxImage
 *
 * Encapsulates the URL, width and height of an image.
 * 
 * Constructor: mxImage
 * 
 * Constructs a new image.
 */
function mxImage(src, width, height)
{
\tthis.src = src;
\tthis.width = width;
\tthis.height = height;
};

/**
 * Variable: src
 *
 * String that specifies the URL of the image.
 */
mxImage.prototype.src = null;

/**
 * Variable: width
 *
 * Integer that specifies the width of the image.
 */
mxImage.prototype.width = null;

/**
 * Variable: height
 *
 * Integer that specifies the height of the image.
 */
mxImage.prototype.height = null;
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDivResizer
 * 
 * Maintains the size of a div element in Internet Explorer. This is a
 * workaround for the right and bottom style being ignored in IE.
 * 
 * If you need a div to cover the scrollwidth and -height of a document,
 * then you can use this class as follows:
 * 
 * (code)
 * var resizer = new mxDivResizer(background);
 * resizer.getDocumentHeight = function()
 * {
 *   return document.body.scrollHeight;
 * }
 * resizer.getDocumentWidth = function()
 * {
 *   return document.body.scrollWidth;
 * }
 * resizer.resize();
 * (end)
 * 
 * Constructor: mxDivResizer
 * 
 * Constructs an object that maintains the size of a div
 * element when the window is being resized. This is only
 * required for Internet Explorer as it ignores the respective
 * stylesheet information for DIV elements.
 * 
 * Parameters:
 * 
 * div - Reference to the DOM node whose size should be maintained.
 * container - Optional Container that contains the div. Default is the
 * window.
 */
function mxDivResizer(div, container)
{
\tif (div.nodeName.toLowerCase() == 'div')
\t{
\t\tif (container == null)
\t\t{
\t\t\tcontainer = window;
\t\t}

\t\tthis.div = div;
\t\tvar style = mxUtils.getCurrentStyle(div);
\t\t
\t\tif (style != null)
\t\t{
\t\t\tthis.resizeWidth = style.width == 'auto';
\t\t\tthis.resizeHeight = style.height == 'auto';
\t\t}
\t\t
\t\tmxEvent.addListener(container, 'resize',
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (!this.handlingResize)
\t\t\t\t{
\t\t\t\t\tthis.handlingResize = true;
\t\t\t\t\tthis.resize();
\t\t\t\t\tthis.handlingResize = false;
\t\t\t\t}
\t\t\t})
\t\t);
\t\t
\t\tthis.resize();
\t}
};

/**
 * Function: resizeWidth
 * 
 * Boolean specifying if the width should be updated.
 */
mxDivResizer.prototype.resizeWidth = true;

/**
 * Function: resizeHeight
 * 
 * Boolean specifying if the height should be updated.
 */
mxDivResizer.prototype.resizeHeight = true;

/**
 * Function: handlingResize
 * 
 * Boolean specifying if the width should be updated.
 */
mxDivResizer.prototype.handlingResize = false;

/**
 * Function: resize
 * 
 * Updates the style of the DIV after the window has been resized.
 */
mxDivResizer.prototype.resize = function()
{
\tvar w = this.getDocumentWidth();
\tvar h = this.getDocumentHeight();

\tvar l = parseInt(this.div.style.left);
\tvar r = parseInt(this.div.style.right);
\tvar t = parseInt(this.div.style.top);
\tvar b = parseInt(this.div.style.bottom);
\t
\tif (this.resizeWidth &&
\t\t!isNaN(l) &&
\t\t!isNaN(r) &&
\t\tl >= 0 &&
\t\tr >= 0 &&
\t\tw - r - l > 0)
\t{
\t\tthis.div.style.width = (w - r - l)+'px';
\t}
\t
\tif (this.resizeHeight &&
\t\t!isNaN(t) &&
\t\t!isNaN(b) &&
\t\tt >= 0 &&
\t\tb >= 0 &&
\t\th - t - b > 0)
\t{
\t\tthis.div.style.height = (h - t - b)+'px';
\t}
};

/**
 * Function: getDocumentWidth
 * 
 * Hook for subclassers to return the width of the document (without
 * scrollbars).
 */
mxDivResizer.prototype.getDocumentWidth = function()
{
\treturn document.body.clientWidth;
};

/**
 * Function: getDocumentHeight
 * 
 * Hook for subclassers to return the height of the document (without
 * scrollbars).
 */
mxDivResizer.prototype.getDocumentHeight = function()
{
\treturn document.body.clientHeight;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDragSource
 * 
 * Wrapper to create a drag source from a DOM element so that the element can
 * be dragged over a graph and dropped into the graph as a new cell.
 * 
 * Problem is that in the dropHandler the current preview location is not
 * available, so the preview and the dropHandler must match.
 * 
 * Constructor: mxDragSource
 * 
 * Constructs a new drag source for the given element.
 */
function mxDragSource(element, dropHandler)
{
\tthis.element = element;
\tthis.dropHandler = dropHandler;
\t
\t// Handles a drag gesture on the element
\tmxEvent.addGestureListeners(element, mxUtils.bind(this, function(evt)
\t{
\t\tthis.mouseDown(evt);
\t}));
\t
\t// Prevents native drag and drop
\tmxEvent.addListener(element, 'dragstart', function(evt)
\t{
\t\tmxEvent.consume(evt);
\t});
\t
\tthis.eventConsumer = function(sender, evt)
\t{
\t\tvar evtName = evt.getProperty('eventName');
\t\tvar me = evt.getProperty('event');
\t\t
\t\tif (evtName != mxEvent.MOUSE_DOWN)
\t\t{
\t\t\tme.consume();
\t\t}
\t};
};

/**
 * Variable: element
 *
 * Reference to the DOM node which was made draggable.
 */
mxDragSource.prototype.element = null;

/**
 * Variable: dropHandler
 *
 * Holds the DOM node that is used to represent the drag preview. If this is
 * null then the source element will be cloned and used for the drag preview.
 */
mxDragSource.prototype.dropHandler = null;

/**
 * Variable: dragOffset
 *
 * <mxPoint> that specifies the offset of the <dragElement>. Default is null.
 */
mxDragSource.prototype.dragOffset = null;

/**
 * Variable: dragElement
 *
 * Holds the DOM node that is used to represent the drag preview. If this is
 * null then the source element will be cloned and used for the drag preview.
 */
mxDragSource.prototype.dragElement = null;

/**
 * Variable: previewElement
 *
 * Optional <mxRectangle> that specifies the unscaled size of the preview.
 */
mxDragSource.prototype.previewElement = null;

/**
 * Variable: previewOffset
 *
 * Optional <mxPoint> that specifies the offset of the preview in pixels.
 */
mxDragSource.prototype.previewOffset = null;

/**
 * Variable: enabled
 *
 * Specifies if this drag source is enabled. Default is true.
 */
mxDragSource.prototype.enabled = true;

/**
 * Variable: currentGraph
 *
 * Reference to the <mxGraph> that is the current drop target.
 */
mxDragSource.prototype.currentGraph = null;

/**
 * Variable: currentDropTarget
 *
 * Holds the current drop target under the mouse.
 */
mxDragSource.prototype.currentDropTarget = null;

/**
 * Variable: currentPoint
 *
 * Holds the current drop location.
 */
mxDragSource.prototype.currentPoint = null;

/**
 * Variable: currentGuide
 *
 * Holds an <mxGuide> for the <currentGraph> if <dragPreview> is not null.
 */
mxDragSource.prototype.currentGuide = null;

/**
 * Variable: currentGuide
 *
 * Holds an <mxGuide> for the <currentGraph> if <dragPreview> is not null.
 */
mxDragSource.prototype.currentHighlight = null;

/**
 * Variable: autoscroll
 *
 * Specifies if the graph should scroll automatically. Default is true.
 */
mxDragSource.prototype.autoscroll = true;

/**
 * Variable: guidesEnabled
 *
 * Specifies if <mxGuide> should be enabled. Default is true.
 */
mxDragSource.prototype.guidesEnabled = true;

/**
 * Variable: gridEnabled
 *
 * Specifies if the grid should be allowed. Default is true.
 */
mxDragSource.prototype.gridEnabled = true;

/**
 * Variable: highlightDropTargets
 *
 * Specifies if drop targets should be highlighted. Default is true.
 */
mxDragSource.prototype.highlightDropTargets = true;

/**
 * Variable: dragElementZIndex
 * 
 * ZIndex for the drag element. Default is 100.
 */
mxDragSource.prototype.dragElementZIndex = 100;

/**
 * Variable: dragElementOpacity
 * 
 * Opacity of the drag element in %. Default is 70.
 */
mxDragSource.prototype.dragElementOpacity = 70;

/**
 * Variable: checkEventSource
 * 
 * Whether the event source should be checked in <graphContainerEvent>. Default
 * is true.
 */
mxDragSource.prototype.checkEventSource = true;

/**
 * Function: isEnabled
 * 
 * Returns <enabled>.
 */
mxDragSource.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Sets <enabled>.
 */
mxDragSource.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: isGuidesEnabled
 * 
 * Returns <guidesEnabled>.
 */
mxDragSource.prototype.isGuidesEnabled = function()
{
\treturn this.guidesEnabled;
};

/**
 * Function: setGuidesEnabled
 * 
 * Sets <guidesEnabled>.
 */
mxDragSource.prototype.setGuidesEnabled = function(value)
{
\tthis.guidesEnabled = value;
};

/**
 * Function: isGridEnabled
 * 
 * Returns <gridEnabled>.
 */
mxDragSource.prototype.isGridEnabled = function()
{
\treturn this.gridEnabled;
};

/**
 * Function: setGridEnabled
 * 
 * Sets <gridEnabled>.
 */
mxDragSource.prototype.setGridEnabled = function(value)
{
\tthis.gridEnabled = value;
};

/**
 * Function: getGraphForEvent
 * 
 * Returns the graph for the given mouse event. This implementation returns
 * null.
 */
mxDragSource.prototype.getGraphForEvent = function(evt)
{
\treturn null;
};

/**
 * Function: getDropTarget
 * 
 * Returns the drop target for the given graph and coordinates. This
 * implementation uses <mxGraph.getCellAt>.
 */
mxDragSource.prototype.getDropTarget = function(graph, x, y, evt)
{
\treturn graph.getCellAt(x, y);
};

/**
 * Function: createDragElement
 * 
 * Creates and returns a clone of the <dragElementPrototype> or the <element>
 * if the former is not defined.
 */
mxDragSource.prototype.createDragElement = function(evt)
{
\treturn this.element.cloneNode(true);
};

/**
 * Function: createPreviewElement
 * 
 * Creates and returns an element which can be used as a preview in the given
 * graph.
 */
mxDragSource.prototype.createPreviewElement = function(graph)
{
\treturn null;
};

/**
 * Function: isActive
 * 
 * Returns true if this drag source is active.
 */
mxDragSource.prototype.isActive = function()
{
\treturn this.mouseMoveHandler != null;
};

/**
 * Function: reset
 * 
 * Stops and removes everything and restores the state of the object.
 */
mxDragSource.prototype.reset = function()
{
\tif (this.currentGraph != null)
\t{
\t\tthis.dragExit(this.currentGraph);
\t\tthis.currentGraph = null;
\t}
\t
\tthis.removeDragElement();
\tthis.removeListeners();
\tthis.stopDrag();
};

/**
 * Function: mouseDown
 * 
 * Returns the drop target for the given graph and coordinates. This
 * implementation uses <mxGraph.getCellAt>.
 * 
 * To ignore popup menu events for a drag source, this function can be
 * overridden as follows.
 * 
 * (code)
 * var mouseDown = dragSource.mouseDown;
 * 
 * dragSource.mouseDown = function(evt)
 * {
 *   if (!mxEvent.isPopupTrigger(evt))
 *   {
 *     mouseDown.apply(this, arguments);
 *   }
 * };
 * (end)
 */
mxDragSource.prototype.mouseDown = function(evt)
{
\tif (this.enabled && !mxEvent.isConsumed(evt) && this.mouseMoveHandler == null)
\t{
\t\tthis.startDrag(evt);
\t\tthis.mouseMoveHandler = mxUtils.bind(this, this.mouseMove);
\t\tthis.mouseUpHandler = mxUtils.bind(this, this.mouseUp);\t\t
\t\tmxEvent.addGestureListeners(document, null, this.mouseMoveHandler, this.mouseUpHandler);
\t\t
\t\tif (mxClient.IS_TOUCH && !mxEvent.isMouseEvent(evt))
\t\t{
\t\t\tthis.eventSource = mxEvent.getSource(evt);
\t\t\tmxEvent.addGestureListeners(this.eventSource, null, this.mouseMoveHandler, this.mouseUpHandler);
\t\t}
\t}
};

/**
 * Function: startDrag
 * 
 * Creates the <dragElement> using <createDragElement>.
 */
mxDragSource.prototype.startDrag = function(evt)
{
\tthis.dragElement = this.createDragElement(evt);
\tthis.dragElement.style.position = 'absolute';
\tthis.dragElement.style.zIndex = this.dragElementZIndex;
\tmxUtils.setOpacity(this.dragElement, this.dragElementOpacity);

\tif (this.checkEventSource && mxClient.IS_SVG)
\t{
\t\tthis.dragElement.style.pointerEvents = 'none';
\t}
};

/**
 * Function: stopDrag
 * 
 * Invokes <removeDragElement>.
 */
mxDragSource.prototype.stopDrag = function()
{
\t// LATER: This used to have a mouse event. If that is still needed we need to add another
\t// final call to the DnD protocol to add a cleanup step in the case of escape press, which
\t// is not associated with a mouse event and which currently calles this method.
\tthis.removeDragElement();
};

/**
 * Function: removeDragElement
 * 
 * Removes and destroys the <dragElement>.
 */
mxDragSource.prototype.removeDragElement = function()
{
\tif (this.dragElement != null)
\t{
\t\tif (this.dragElement.parentNode != null)
\t\t{
\t\t\tthis.dragElement.parentNode.removeChild(this.dragElement);
\t\t}
\t\t
\t\tthis.dragElement = null;
\t}
};

/**
 * Function: getElementForEvent
 * 
 * Returns the topmost element under the given event.
 */
mxDragSource.prototype.getElementForEvent = function(evt)
{
\treturn ((mxEvent.isTouchEvent(evt) || mxEvent.isPenEvent(evt)) ?
\t\t\tdocument.elementFromPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt)) :
\t\t\t\tmxEvent.getSource(evt));
};

/**
 * Function: graphContainsEvent
 * 
 * Returns true if the given graph contains the given event.
 */
mxDragSource.prototype.graphContainsEvent = function(graph, evt)
{
\tvar x = mxEvent.getClientX(evt);
\tvar y = mxEvent.getClientY(evt);
\tvar offset = mxUtils.getOffset(graph.container);
\tvar origin = mxUtils.getScrollOrigin();
\tvar elt = this.getElementForEvent(evt);
\t
\tif (this.checkEventSource)
\t{
\t\twhile (elt != null && elt != graph.container)
\t\t{
\t\t\telt = elt.parentNode;
\t\t}
\t}

\t// Checks if event is inside the bounds of the graph container
\treturn elt != null && x >= offset.x - origin.x && y >= offset.y - origin.y &&
\t\tx <= offset.x - origin.x + graph.container.offsetWidth &&
\t\ty <= offset.y - origin.y + graph.container.offsetHeight;
};

/**
 * Function: mouseMove
 * 
 * Gets the graph for the given event using <getGraphForEvent>, updates the
 * <currentGraph>, calling <dragEnter> and <dragExit> on the new and old graph,
 * respectively, and invokes <dragOver> if <currentGraph> is not null.
 */
mxDragSource.prototype.mouseMove = function(evt)
{
\tvar graph = this.getGraphForEvent(evt);
\t
\t// Checks if event is inside the bounds of the graph container
\tif (graph != null && !this.graphContainsEvent(graph, evt))
\t{
\t\tgraph = null;
\t}

\tif (graph != this.currentGraph)
\t{
\t\tif (this.currentGraph != null)
\t\t{
\t\t\tthis.dragExit(this.currentGraph, evt);
\t\t}
\t\t
\t\tthis.currentGraph = graph;
\t\t
\t\tif (this.currentGraph != null)
\t\t{
\t\t\tthis.dragEnter(this.currentGraph, evt);
\t\t}
\t}
\t
\tif (this.currentGraph != null)
\t{
\t\tthis.dragOver(this.currentGraph, evt);
\t}

\tif (this.dragElement != null && (this.previewElement == null || this.previewElement.style.visibility != 'visible'))
\t{
\t\tvar x = mxEvent.getClientX(evt);
\t\tvar y = mxEvent.getClientY(evt);
\t\t
\t\tif (this.dragElement.parentNode == null)
\t\t{
\t\t\tdocument.body.appendChild(this.dragElement);
\t\t}

\t\tthis.dragElement.style.visibility = 'visible';
\t\t
\t\tif (this.dragOffset != null)
\t\t{
\t\t\tx += this.dragOffset.x;
\t\t\ty += this.dragOffset.y;
\t\t}
\t\t
\t\tvar offset = mxUtils.getDocumentScrollOrigin(document);
\t\t
\t\tthis.dragElement.style.left = (x + offset.x) + 'px';
\t\tthis.dragElement.style.top = (y + offset.y) + 'px';
\t}
\telse if (this.dragElement != null)
\t{
\t\tthis.dragElement.style.visibility = 'hidden';
\t}
\t
\tmxEvent.consume(evt);
};

/**
 * Function: mouseUp
 * 
 * Processes the mouse up event and invokes <drop>, <dragExit> and <stopDrag>
 * as required.
 */
mxDragSource.prototype.mouseUp = function(evt)
{
\tif (this.currentGraph != null)
\t{
\t\tif (this.currentPoint != null && (this.previewElement == null ||
\t\t\tthis.previewElement.style.visibility != 'hidden'))
\t\t{
\t\t\tvar scale = this.currentGraph.view.scale;
\t\t\tvar tr = this.currentGraph.view.translate;
\t\t\tvar x = this.currentPoint.x / scale - tr.x;
\t\t\tvar y = this.currentPoint.y / scale - tr.y;
\t\t\t
\t\t\tthis.drop(this.currentGraph, evt, this.currentDropTarget, x, y);
\t\t}
\t\t
\t\tthis.dragExit(this.currentGraph);
\t\tthis.currentGraph = null;
\t}

\tthis.stopDrag();
\tthis.removeListeners();
\t
\tmxEvent.consume(evt);
};

/**
 * Function: removeListeners
 * 
 * Actives the given graph as a drop target.
 */
mxDragSource.prototype.removeListeners = function()
{
\tif (this.eventSource != null)
\t{
\t\tmxEvent.removeGestureListeners(this.eventSource, null, this.mouseMoveHandler, this.mouseUpHandler);
\t\tthis.eventSource = null;
\t}
\t
\tmxEvent.removeGestureListeners(document, null, this.mouseMoveHandler, this.mouseUpHandler);
\tthis.mouseMoveHandler = null;
\tthis.mouseUpHandler = null;
};

/**
 * Function: dragEnter
 * 
 * Actives the given graph as a drop target.
 */
mxDragSource.prototype.dragEnter = function(graph, evt)
{
\tgraph.isMouseDown = true;
\tgraph.isMouseTrigger = mxEvent.isMouseEvent(evt);
\tthis.previewElement = this.createPreviewElement(graph);
\t
\tif (this.previewElement != null && this.checkEventSource && mxClient.IS_SVG)
\t{
\t\tthis.previewElement.style.pointerEvents = 'none';
\t}
\t
\t// Guide is only needed if preview element is used
\tif (this.isGuidesEnabled() && this.previewElement != null)
\t{
\t\tthis.currentGuide = new mxGuide(graph, graph.graphHandler.getGuideStates());
\t}
\t
\tif (this.highlightDropTargets)
\t{
\t\tthis.currentHighlight = new mxCellHighlight(graph, mxConstants.DROP_TARGET_COLOR);
\t}
\t
\t// Consumes all events in the current graph before they are fired
\tgraph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.eventConsumer);
};

/**
 * Function: dragExit
 * 
 * Deactivates the given graph as a drop target.
 */
mxDragSource.prototype.dragExit = function(graph, evt)
{
\tthis.currentDropTarget = null;
\tthis.currentPoint = null;
\tgraph.isMouseDown = false;
\t
\t// Consumes all events in the current graph before they are fired
\tgraph.removeListener(this.eventConsumer);
\t
\tif (this.previewElement != null)
\t{
\t\tif (this.previewElement.parentNode != null)
\t\t{
\t\t\tthis.previewElement.parentNode.removeChild(this.previewElement);
\t\t}
\t\t
\t\tthis.previewElement = null;
\t}
\t
\tif (this.currentGuide != null)
\t{
\t\tthis.currentGuide.destroy();
\t\tthis.currentGuide = null;
\t}
\t
\tif (this.currentHighlight != null)
\t{
\t\tthis.currentHighlight.destroy();
\t\tthis.currentHighlight = null;
\t}
};

/**
 * Function: dragOver
 * 
 * Implements autoscroll, updates the <currentPoint>, highlights any drop
 * targets and updates the preview.
 */
mxDragSource.prototype.dragOver = function(graph, evt)
{
\tvar offset = mxUtils.getOffset(graph.container);
\tvar origin = mxUtils.getScrollOrigin(graph.container);
\tvar x = mxEvent.getClientX(evt) - offset.x + origin.x - graph.panDx;
\tvar y = mxEvent.getClientY(evt) - offset.y + origin.y - graph.panDy;

\tif (graph.autoScroll && (this.autoscroll == null || this.autoscroll))
\t{
\t\tgraph.scrollPointToVisible(x, y, graph.autoExtend);
\t}

\t// Highlights the drop target under the mouse
\tif (this.currentHighlight != null && graph.isDropEnabled())
\t{
\t\tthis.currentDropTarget = this.getDropTarget(graph, x, y, evt);
\t\tvar state = graph.getView().getState(this.currentDropTarget);
\t\tthis.currentHighlight.highlight(state);
\t}

\t// Updates the location of the preview
\tif (this.previewElement != null)
\t{
\t\tif (this.previewElement.parentNode == null)
\t\t{
\t\t\tgraph.container.appendChild(this.previewElement);
\t\t\t
\t\t\tthis.previewElement.style.zIndex = '3';
\t\t\tthis.previewElement.style.position = 'absolute';
\t\t}
\t\t
\t\tvar gridEnabled = this.isGridEnabled() && graph.isGridEnabledEvent(evt);
\t\tvar hideGuide = true;

\t\t// Grid and guides
\t\tif (this.currentGuide != null && this.currentGuide.isEnabledForEvent(evt))
\t\t{
\t\t\t// LATER: HTML preview appears smaller than SVG preview
\t\t\tvar w = parseInt(this.previewElement.style.width);
\t\t\tvar h = parseInt(this.previewElement.style.height);
\t\t\tvar bounds = new mxRectangle(0, 0, w, h);
\t\t\tvar delta = new mxPoint(x, y);
\t\t\tdelta = this.currentGuide.move(bounds, delta, gridEnabled, true);
\t\t\thideGuide = false;
\t\t\tx = delta.x;
\t\t\ty = delta.y;
\t\t}
\t\telse if (gridEnabled)
\t\t{
\t\t\tvar scale = graph.view.scale;
\t\t\tvar tr = graph.view.translate;
\t\t\tvar off = graph.gridSize / 2;
\t\t\tx = (graph.snap(x / scale - tr.x - off) + tr.x) * scale;
\t\t\ty = (graph.snap(y / scale - tr.y - off) + tr.y) * scale;
\t\t}
\t\t
\t\tif (this.currentGuide != null && hideGuide)
\t\t{
\t\t\tthis.currentGuide.hide();
\t\t}
\t\t
\t\tif (this.previewOffset != null)
\t\t{
\t\t\tx += this.previewOffset.x;
\t\t\ty += this.previewOffset.y;
\t\t}

\t\tthis.previewElement.style.left = Math.round(x) + 'px';
\t\tthis.previewElement.style.top = Math.round(y) + 'px';
\t\tthis.previewElement.style.visibility = 'visible';
\t}
\t
\tthis.currentPoint = new mxPoint(x, y);
};

/**
 * Function: drop
 * 
 * Returns the drop target for the given graph and coordinates. This
 * implementation uses <mxGraph.getCellAt>.
 */
mxDragSource.prototype.drop = function(graph, evt, dropTarget, x, y)
{
\tthis.dropHandler.apply(this, arguments);
\t
\t// Had to move this to after the insert because it will
\t// affect the scrollbars of the window in IE to try and
\t// make the complete container visible.
\t// LATER: Should be made optional.
\tif (graph.container.style.visibility != 'hidden')
\t{
\t\tgraph.container.focus();
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxToolbar
 * 
 * Creates a toolbar inside a given DOM node. The toolbar may contain icons,
 * buttons and combo boxes.
 * 
 * Event: mxEvent.SELECT
 * 
 * Fires when an item was selected in the toolbar. The <code>function</code>
 * property contains the function that was selected in <selectMode>.
 * 
 * Constructor: mxToolbar
 * 
 * Constructs a toolbar in the specified container.
 *
 * Parameters:
 *
 * container - DOM node that contains the toolbar.
 */
function mxToolbar(container)
{
\tthis.container = container;
};

/**
 * Extends mxEventSource.
 */
mxToolbar.prototype = new mxEventSource();
mxToolbar.prototype.constructor = mxToolbar;

/**
 * Variable: container
 * 
 * Reference to the DOM nodes that contains the toolbar.
 */
mxToolbar.prototype.container = null;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxToolbar.prototype.enabled = true;

/**
 * Variable: noReset
 * 
 * Specifies if <resetMode> requires a forced flag of true for resetting
 * the current mode in the toolbar. Default is false. This is set to true
 * if the toolbar item is double clicked to avoid a reset after a single
 * use of the item.
 */
mxToolbar.prototype.noReset = false;

/**
 * Variable: updateDefaultMode
 * 
 * Boolean indicating if the default mode should be the last selected
 * switch mode or the first inserted switch mode. Default is true, that
 * is the last selected switch mode is the default mode. The default mode
 * is the mode to be selected after a reset of the toolbar. If this is
 * false, then the default mode is the first inserted mode item regardless
 * of what was last selected. Otherwise, the selected item after a reset is
 * the previously selected item.
 */
mxToolbar.prototype.updateDefaultMode = true;

/**
 * Function: addItem
 * 
 * Adds the given function as an image with the specified title and icon
 * and returns the new image node.
 * 
 * Parameters:
 * 
 * title - Optional string that is used as the tooltip.
 * icon - Optional URL of the image to be used. If no URL is given, then a
 * button is created.
 * funct - Function to execute on a mouse click.
 * pressedIcon - Optional URL of the pressed image. Default is a gray
 * background.
 * style - Optional style classname. Default is mxToolbarItem.
 * factoryMethod - Optional factory method for popup menu, eg.
 * function(menu, evt, cell) { menu.addItem('Hello, World!'); }
 */
mxToolbar.prototype.addItem = function(title, icon, funct, pressedIcon, style, factoryMethod)
{
\tvar img = document.createElement((icon != null) ? 'img' : 'button');
\tvar initialClassName = style || ((factoryMethod != null) ?
\t\t\t'mxToolbarMode' : 'mxToolbarItem');
\timg.className = initialClassName;
\timg.setAttribute('src', icon);
\t
\tif (title != null)
\t{
\t\tif (icon != null)
\t\t{
\t\t\timg.setAttribute('title', title);
\t\t}
\t\telse
\t\t{
\t\t\tmxUtils.write(img, title);
\t\t}
\t}
\t
\tthis.container.appendChild(img);

\t// Invokes the function on a click on the toolbar item
\tif (funct != null)
\t{
\t\tmxEvent.addListener(img, 'click', funct);
\t\t
\t\tif (mxClient.IS_TOUCH)
\t\t{
\t\t\tmxEvent.addListener(img, 'touchend', funct);
\t\t}
\t}

\tvar mouseHandler = mxUtils.bind(this, function(evt)
\t{
\t\tif (pressedIcon != null)
\t\t{
\t\t\timg.setAttribute('src', icon);
\t\t}
\t\telse
\t\t{
\t\t\timg.style.backgroundColor = '';
\t\t}
\t});

\t// Highlights the toolbar item with a gray background
\t// while it is being clicked with the mouse
\tmxEvent.addGestureListeners(img, mxUtils.bind(this, function(evt)
\t{
\t\tif (pressedIcon != null)
\t\t{
\t\t\timg.setAttribute('src', pressedIcon);
\t\t}
\t\telse
\t\t{
\t\t\timg.style.backgroundColor = 'gray';
\t\t}
\t\t
\t\t// Popup Menu
\t\tif (factoryMethod != null)
\t\t{
\t\t\tif (this.menu == null)
\t\t\t{
\t\t\t\tthis.menu = new mxPopupMenu();
\t\t\t\tthis.menu.init();
\t\t\t}
\t\t\t
\t\t\tvar last = this.currentImg;
\t\t\t
\t\t\tif (this.menu.isMenuShowing())
\t\t\t{
\t\t\t\tthis.menu.hideMenu();
\t\t\t}
\t\t\t
\t\t\tif (last != img)
\t\t\t{
\t\t\t\t// Redirects factory method to local factory method
\t\t\t\tthis.currentImg = img;
\t\t\t\tthis.menu.factoryMethod = factoryMethod;
\t\t\t\t
\t\t\t\tvar point = new mxPoint(
\t\t\t\t\timg.offsetLeft,
\t\t\t\t\timg.offsetTop + img.offsetHeight);
\t\t\t\tthis.menu.popup(point.x, point.y, null, evt);

\t\t\t\t// Sets and overrides to restore classname
\t\t\t\tif (this.menu.isMenuShowing())
\t\t\t\t{
\t\t\t\t\timg.className = initialClassName + 'Selected';
\t\t\t\t\t
\t\t\t\t\tthis.menu.hideMenu = function()
\t\t\t\t\t{
\t\t\t\t\t\tmxPopupMenu.prototype.hideMenu.apply(this);
\t\t\t\t\t\timg.className = initialClassName;
\t\t\t\t\t\tthis.currentImg = null;
\t\t\t\t\t};
\t\t\t\t}
\t\t\t}
\t\t}
\t}), null, mouseHandler);

\tmxEvent.addListener(img, 'mouseout', mouseHandler);
\t
\treturn img;
};

/**
 * Function: addCombo
 * 
 * Adds and returns a new SELECT element using the given style. The element
 * is placed inside a DIV with the mxToolbarComboContainer style classname.
 * 
 * Parameters:
 * 
 * style - Optional style classname. Default is mxToolbarCombo.
 */
mxToolbar.prototype.addCombo = function(style)
{
\tvar div = document.createElement('div');
\tdiv.style.display = 'inline';
\tdiv.className = 'mxToolbarComboContainer';
\t
\tvar select = document.createElement('select');
\tselect.className = style || 'mxToolbarCombo';
\tdiv.appendChild(select);
\t
\tthis.container.appendChild(div);
\t
\treturn select;
};

/**
 * Function: addActionCombo
 * 
 * Adds and returns a new SELECT element using the given title as the
 * default element. The selection is reset to this element after each
 * change.
 * 
 * Parameters:
 * 
 * title - String that specifies the title of the default element.
 * style - Optional style classname. Default is mxToolbarCombo.
 */
mxToolbar.prototype.addActionCombo = function(title, style)
{
\tvar select = document.createElement('select');
\tselect.className = style || 'mxToolbarCombo';
\tthis.addOption(select, title, null);
\t
\tmxEvent.addListener(select, 'change', function(evt)
\t{
\t\tvar value = select.options[select.selectedIndex];
\t\tselect.selectedIndex = 0;
\t\t
\t\tif (value.funct != null)
\t\t{
\t\t\tvalue.funct(evt);
\t\t}
\t});
\t
\tthis.container.appendChild(select);
\t
\treturn select;
};

/**
 * Function: addOption
 * 
 * Adds and returns a new OPTION element inside the given SELECT element.
 * If the given value is a function then it is stored in the option's funct
 * field.
 * 
 * Parameters:
 * 
 * combo - SELECT element that will contain the new entry.
 * title - String that specifies the title of the option.
 * value - Specifies the value associated with this option.
 */
mxToolbar.prototype.addOption = function(combo, title, value)
{
\tvar option = document.createElement('option');
\tmxUtils.writeln(option, title);
\t
\tif (typeof(value) == 'function')
\t{
\t\toption.funct = value;
\t}
\telse
\t{
\t\toption.setAttribute('value', value);
\t}
\t
\tcombo.appendChild(option);
\t
\treturn option;
};

/**
 * Function: addSwitchMode
 * 
 * Adds a new selectable item to the toolbar. Only one switch mode item may
 * be selected at a time. The currently selected item is the default item
 * after a reset of the toolbar.
 */
mxToolbar.prototype.addSwitchMode = function(title, icon, funct, pressedIcon, style)
{
\tvar img = document.createElement('img');
\timg.initialClassName = style || 'mxToolbarMode';
\timg.className = img.initialClassName;
\timg.setAttribute('src', icon);
\timg.altIcon = pressedIcon;
\t
\tif (title != null)
\t{
\t\timg.setAttribute('title', title);
\t}
\t
\tmxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
\t{
\t\tvar tmp = this.selectedMode.altIcon;
\t\t
\t\tif (tmp != null)
\t\t{
\t\t\tthis.selectedMode.altIcon = this.selectedMode.getAttribute('src');
\t\t\tthis.selectedMode.setAttribute('src', tmp);
\t\t}
\t\telse
\t\t{
\t\t\tthis.selectedMode.className = this.selectedMode.initialClassName;
\t\t}
\t\t
\t\tif (this.updateDefaultMode)
\t\t{
\t\t\tthis.defaultMode = img;
\t\t}
\t\t
\t\tthis.selectedMode = img;
\t\t
\t\tvar tmp = img.altIcon;
\t\t
\t\tif (tmp != null)
\t\t{
\t\t\timg.altIcon = img.getAttribute('src');
\t\t\timg.setAttribute('src', tmp);
\t\t}
\t\telse
\t\t{
\t\t\timg.className = img.initialClassName+'Selected';
\t\t}
\t\t
\t\tthis.fireEvent(new mxEventObject(mxEvent.SELECT));
\t\tfunct();
\t}));
\t
\tthis.container.appendChild(img);
\t
\tif (this.defaultMode == null)
\t{
\t\tthis.defaultMode = img;
\t\t
\t\t// Function should fire only once so
\t\t// do not pass it with the select event
\t\tthis.selectMode(img);
\t\tfunct();
\t}
\t
\treturn img;
};

/**
 * Function: addMode
 * 
 * Adds a new item to the toolbar. The selection is typically reset after
 * the item has been consumed, for example by adding a new vertex to the
 * graph. The reset is not carried out if the item is double clicked.
 * 
 * The function argument uses the following signature: funct(evt, cell) where
 * evt is the native mouse event and cell is the cell under the mouse.
 */
mxToolbar.prototype.addMode = function(title, icon, funct, pressedIcon, style, toggle)
{
\ttoggle = (toggle != null) ? toggle : true;
\tvar img = document.createElement((icon != null) ? 'img' : 'button');
\t
\timg.initialClassName = style || 'mxToolbarMode';
\timg.className = img.initialClassName;
\timg.setAttribute('src', icon);
\timg.altIcon = pressedIcon;

\tif (title != null)
\t{
\t\timg.setAttribute('title', title);
\t}
\t
\tif (this.enabled && toggle)
\t{
\t\tmxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.selectMode(img, funct);
\t\t\tthis.noReset = false;
\t\t}));
\t\t
\t\tmxEvent.addListener(img, 'dblclick', mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.selectMode(img, funct);
\t\t\tthis.noReset = true;
\t\t}));
\t\t
\t\tif (this.defaultMode == null)
\t\t{
\t\t\tthis.defaultMode = img;
\t\t\tthis.defaultFunction = funct;
\t\t\tthis.selectMode(img, funct);
\t\t}
\t}

\tthis.container.appendChild(img);\t\t\t\t\t

\treturn img;
};

/**
 * Function: selectMode
 * 
 * Resets the state of the previously selected mode and displays the given
 * DOM node as selected. This function fires a select event with the given
 * function as a parameter.
 */
mxToolbar.prototype.selectMode = function(domNode, funct)
{
\tif (this.selectedMode != domNode)
\t{
\t\tif (this.selectedMode != null)
\t\t{
\t\t\tvar tmp = this.selectedMode.altIcon;
\t\t\t
\t\t\tif (tmp != null)
\t\t\t{
\t\t\t\tthis.selectedMode.altIcon = this.selectedMode.getAttribute('src');
\t\t\t\tthis.selectedMode.setAttribute('src', tmp);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.selectedMode.className = this.selectedMode.initialClassName;
\t\t\t}
\t\t}
\t\t
\t\tthis.selectedMode = domNode;
\t\tvar tmp = this.selectedMode.altIcon;
\t\t
\t\tif (tmp != null)
\t\t{
\t\t\tthis.selectedMode.altIcon = this.selectedMode.getAttribute('src');
\t\t\tthis.selectedMode.setAttribute('src', tmp);
\t\t}
\t\telse
\t\t{
\t\t\tthis.selectedMode.className = this.selectedMode.initialClassName+'Selected';
\t\t}
\t\t
\t\tthis.fireEvent(new mxEventObject(mxEvent.SELECT, \"function\", funct));
\t}
};

/**
 * Function: resetMode
 * 
 * Selects the default mode and resets the state of the previously selected
 * mode.
 */
mxToolbar.prototype.resetMode = function(forced)
{
\tif ((forced || !this.noReset) && this.selectedMode != this.defaultMode)
\t{
\t\t// The last selected switch mode will be activated
\t\t// so the function was already executed and is
\t\t// no longer required here
\t\tthis.selectMode(this.defaultMode, this.defaultFunction);
\t}
};

/**
 * Function: addSeparator
 * 
 * Adds the specifies image as a separator.
 * 
 * Parameters:
 * 
 * icon - URL of the separator icon.
 */
mxToolbar.prototype.addSeparator = function(icon)
{
\treturn this.addItem(null, icon, null);
};

/**
 * Function: addBreak
 * 
 * Adds a break to the container.
 */
mxToolbar.prototype.addBreak = function()
{
\tmxUtils.br(this.container);
};

/**
 * Function: addLine
 * 
 * Adds a horizontal line to the container.
 */
mxToolbar.prototype.addLine = function()
{
\tvar hr = document.createElement('hr');
\t
\thr.style.marginRight = '6px';
\thr.setAttribute('size', '1');
\t
\tthis.container.appendChild(hr);
};

/**
 * Function: destroy
 * 
 * Removes the toolbar and all its associated resources.
 */
mxToolbar.prototype.destroy = function ()
{
\tmxEvent.release(this.container);
\tthis.container = null;
\tthis.defaultMode = null;
\tthis.defaultFunction = null;
\tthis.selectedMode = null;
\t
\tif (this.menu != null)
\t{
\t\tthis.menu.destroy();
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxUndoableEdit
 * 
 * Implements a composite undoable edit. Here is an example for a custom change
 * which gets executed via the model:
 * 
 * (code)
 * function CustomChange(model, name)
 * {
 *   this.model = model;
 *   this.name = name;
 *   this.previous = name;
 * };
 * 
 * CustomChange.prototype.execute = function()
 * {
 *   var tmp = this.model.name;
 *   this.model.name = this.previous;
 *   this.previous = tmp;
 * };
 * 
 * var name = prompt('Enter name');
 * graph.model.execute(new CustomChange(graph.model, name));
 * (end)
 * 
 * Event: mxEvent.EXECUTED
 * 
 * Fires between START_EDIT and END_EDIT after an atomic change was executed.
 * The <code>change</code> property contains the change that was executed.
 * 
 * Event: mxEvent.START_EDIT
 * 
 * Fires before a set of changes will be executed in <undo> or <redo>.
 * This event contains no properties.
 * 
 * Event: mxEvent.END_EDIT
 *
 * Fires after a set of changeswas executed in <undo> or <redo>.
 * This event contains no properties.
 * 
 * Constructor: mxUndoableEdit
 * 
 * Constructs a new undoable edit for the given source.
 */
function mxUndoableEdit(source, significant)
{
\tthis.source = source;
\tthis.changes = [];
\tthis.significant = (significant != null) ? significant : true;
};

/**
 * Variable: source
 * 
 * Specifies the source of the edit.
 */
mxUndoableEdit.prototype.source = null;

/**
 * Variable: changes
 * 
 * Array that contains the changes that make up this edit. The changes are
 * expected to either have an undo and redo function, or an execute
 * function. Default is an empty array.
 */
mxUndoableEdit.prototype.changes = null;

/**
 * Variable: significant
 * 
 * Specifies if the undoable change is significant.
 * Default is true.
 */
mxUndoableEdit.prototype.significant = null;

/**
 * Variable: undone
 * 
 * Specifies if this edit has been undone. Default is false.
 */
mxUndoableEdit.prototype.undone = false;

/**
 * Variable: redone
 * 
 * Specifies if this edit has been redone. Default is false.
 */
mxUndoableEdit.prototype.redone = false;

/**
 * Function: isEmpty
 * 
 * Returns true if the this edit contains no changes.
 */
mxUndoableEdit.prototype.isEmpty = function()
{
\treturn this.changes.length == 0;
};

/**
 * Function: isSignificant
 * 
 * Returns <significant>.
 */
mxUndoableEdit.prototype.isSignificant = function()
{
\treturn this.significant;
};

/**
 * Function: add
 * 
 * Adds the specified change to this edit. The change is an object that is
 * expected to either have an undo and redo, or an execute function.
 */
mxUndoableEdit.prototype.add = function(change)
{
\tthis.changes.push(change);
};

/**
 * Function: notify
 * 
 * Hook to notify any listeners of the changes after an <undo> or <redo>
 * has been carried out. This implementation is empty.
 */
mxUndoableEdit.prototype.notify = function() { };

/**
 * Function: die
 * 
 * Hook to free resources after the edit has been removed from the command
 * history. This implementation is empty.
 */
mxUndoableEdit.prototype.die = function() { };

/**
 * Function: undo
 * 
 * Undoes all changes in this edit.
 */
mxUndoableEdit.prototype.undo = function()
{
\tif (!this.undone)
\t{
\t\tthis.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
\t\tvar count = this.changes.length;
\t\t
\t\tfor (var i = count - 1; i >= 0; i--)
\t\t{
\t\t\tvar change = this.changes[i];
\t\t\t
\t\t\tif (change.execute != null)
\t\t\t{
\t\t\t\tchange.execute();
\t\t\t}
\t\t\telse if (change.undo != null)
\t\t\t{
\t\t\t\tchange.undo();
\t\t\t}
\t\t\t
\t\t\t// New global executed event
\t\t\tthis.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
\t\t}
\t\t
\t\tthis.undone = true;
\t\tthis.redone = false;
\t\tthis.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
\t}
\t
\tthis.notify();
};

/**
 * Function: redo
 * 
 * Redoes all changes in this edit.
 */
mxUndoableEdit.prototype.redo = function()
{
\tif (!this.redone)
\t{
\t\tthis.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
\t\tvar count = this.changes.length;
\t\t
\t\tfor (var i = 0; i < count; i++)
\t\t{
\t\t\tvar change = this.changes[i];
\t\t\t
\t\t\tif (change.execute != null)
\t\t\t{
\t\t\t\tchange.execute();
\t\t\t}
\t\t\telse if (change.redo != null)
\t\t\t{
\t\t\t\tchange.redo();
\t\t\t}
\t\t\t
\t\t\t// New global executed event
\t\t\tthis.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
\t\t}
\t\t
\t\tthis.undone = false;
\t\tthis.redone = true;
\t\tthis.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
\t}
\t
\tthis.notify();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxUndoManager
 *
 * Implements a command history. When changing the graph model, an
 * <mxUndoableChange> object is created at the start of the transaction (when
 * model.beginUpdate is called). All atomic changes are then added to this
 * object until the last model.endUpdate call, at which point the
 * <mxUndoableEdit> is dispatched in an event, and added to the history inside
 * <mxUndoManager>. This is done by an event listener in
 * <mxEditor.installUndoHandler>.
 * 
 * Each atomic change of the model is represented by an object (eg.
 * <mxRootChange>, <mxChildChange>, <mxTerminalChange> etc) which contains the
 * complete undo information. The <mxUndoManager> also listens to the
 * <mxGraphView> and stores it's changes to the current root as insignificant
 * undoable changes, so that drilling (step into, step up) is undone.
 * 
 * This means when you execute an atomic change on the model, then change the
 * current root on the view and click undo, the change of the root will be
 * undone together with the change of the model so that the display represents
 * the state at which the model was changed. However, these changes are not
 * transmitted for sharing as they do not represent a state change.
 *
 * Example:
 * 
 * When adding an undo manager to a graph, make sure to add it
 * to the model and the view as well to maintain a consistent
 * display across multiple undo/redo steps.
 *
 * (code)
 * var undoManager = new mxUndoManager();
 * var listener = function(sender, evt)
 * {
 *   undoManager.undoableEditHappened(evt.getProperty('edit'));
 * };
 * graph.getModel().addListener(mxEvent.UNDO, listener);
 * graph.getView().addListener(mxEvent.UNDO, listener);
 * (end)
 * 
 * The code creates a function that informs the undoManager
 * of an undoable edit and binds it to the undo event of
 * <mxGraphModel> and <mxGraphView> using
 * <mxEventSource.addListener>.
 * 
 * Event: mxEvent.CLEAR
 * 
 * Fires after <clear> was invoked. This event has no properties.
 * 
 * Event: mxEvent.UNDO
 * 
 * Fires afer a significant edit was undone in <undo>. The <code>edit</code>
 * property contains the <mxUndoableEdit> that was undone.
 * 
 * Event: mxEvent.REDO
 * 
 * Fires afer a significant edit was redone in <redo>. The <code>edit</code>
 * property contains the <mxUndoableEdit> that was redone.
 * 
 * Event: mxEvent.ADD
 * 
 * Fires after an undoable edit was added to the history. The <code>edit</code>
 * property contains the <mxUndoableEdit> that was added.
 * 
 * Constructor: mxUndoManager
 *
 * Constructs a new undo manager with the given history size. If no history
 * size is given, then a default size of 100 steps is used.
 */
function mxUndoManager(size)
{
\tthis.size = (size != null) ? size : 100;
\tthis.clear();
};

/**
 * Extends mxEventSource.
 */
mxUndoManager.prototype = new mxEventSource();
mxUndoManager.prototype.constructor = mxUndoManager;

/**
 * Variable: size
 * 
 * Maximum command history size. 0 means unlimited history. Default is
 * 100.
 */
mxUndoManager.prototype.size = null;

/**
 * Variable: history
 * 
 * Array that contains the steps of the command history.
 */
mxUndoManager.prototype.history = null;

/**
 * Variable: indexOfNextAdd
 * 
 * Index of the element to be added next.
 */
mxUndoManager.prototype.indexOfNextAdd = 0;

/**
 * Function: isEmpty
 * 
 * Returns true if the history is empty.
 */
mxUndoManager.prototype.isEmpty = function()
{
\treturn this.history.length == 0;
};

/**
 * Function: clear
 * 
 * Clears the command history.
 */
mxUndoManager.prototype.clear = function()
{
\tthis.history = [];
\tthis.indexOfNextAdd = 0;
\tthis.fireEvent(new mxEventObject(mxEvent.CLEAR));
};

/**
 * Function: canUndo
 * 
 * Returns true if an undo is possible.
 */
mxUndoManager.prototype.canUndo = function()
{
\treturn this.indexOfNextAdd > 0;
};

/**
 * Function: undo
 * 
 * Undoes the last change.
 */
mxUndoManager.prototype.undo = function()
{
    while (this.indexOfNextAdd > 0)
    {
        var edit = this.history[--this.indexOfNextAdd];
        edit.undo();

\t\tif (edit.isSignificant())
        {
        \tthis.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
            break;
        }
    }
};

/**
 * Function: canRedo
 * 
 * Returns true if a redo is possible.
 */
mxUndoManager.prototype.canRedo = function()
{
\treturn this.indexOfNextAdd < this.history.length;
};

/**
 * Function: redo
 * 
 * Redoes the last change.
 */
mxUndoManager.prototype.redo = function()
{
    var n = this.history.length;
    
    while (this.indexOfNextAdd < n)
    {
        var edit =  this.history[this.indexOfNextAdd++];
        edit.redo();
        
        if (edit.isSignificant())
        {
        \tthis.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit));
            break;
        }
    }
};

/**
 * Function: undoableEditHappened
 * 
 * Method to be called to add new undoable edits to the <history>.
 */
mxUndoManager.prototype.undoableEditHappened = function(undoableEdit)
{
\tthis.trim();
\t
\tif (this.size > 0 &&
\t\tthis.size == this.history.length)
\t{
\t\tthis.history.shift();
\t}
\t
\tthis.history.push(undoableEdit);
\tthis.indexOfNextAdd = this.history.length;
\tthis.fireEvent(new mxEventObject(mxEvent.ADD, 'edit', undoableEdit));
};

/**
 * Function: trim
 * 
 * Removes all pending steps after <indexOfNextAdd> from the history,
 * invoking die on each edit. This is called from <undoableEditHappened>.
 */
mxUndoManager.prototype.trim = function()
{
\tif (this.history.length > this.indexOfNextAdd)
\t{
\t\tvar edits = this.history.splice(this.indexOfNextAdd,
\t\t\tthis.history.length - this.indexOfNextAdd);
\t\t\t
\t\tfor (var i = 0; i < edits.length; i++)
\t\t{
\t\t\tedits[i].die();
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 *
 * Class: mxUrlConverter
 * 
 * Converts relative and absolute URLs to absolute URLs with protocol and domain.
 */
var mxUrlConverter = function()
{
\t// Empty constructor
};

/**
 * Variable: enabled
 * 
 * Specifies if the converter is enabled. Default is true.
 */
mxUrlConverter.prototype.enabled = true;

/**
 * Variable: baseUrl
 * 
 * Specifies the base URL to be used as a prefix for relative URLs.
 */
mxUrlConverter.prototype.baseUrl = null;

/**
 * Variable: baseDomain
 * 
 * Specifies the base domain to be used as a prefix for absolute URLs.
 */
mxUrlConverter.prototype.baseDomain = null;

/**
 * Function: updateBaseUrl
 * 
 * Private helper function to update the base URL.
 */
mxUrlConverter.prototype.updateBaseUrl = function()
{
\tthis.baseDomain = location.protocol + '//' + location.host;
\tthis.baseUrl = this.baseDomain + location.pathname;
\tvar tmp = this.baseUrl.lastIndexOf('/');
\t
\t// Strips filename etc
\tif (tmp > 0)
\t{
\t\tthis.baseUrl = this.baseUrl.substring(0, tmp + 1);
\t}
};

/**
 * Function: isEnabled
 * 
 * Returns <enabled>.
 */
mxUrlConverter.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Sets <enabled>.
 */
mxUrlConverter.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: getBaseUrl
 * 
 * Returns <baseUrl>.
 */
mxUrlConverter.prototype.getBaseUrl = function()
{
\treturn this.baseUrl;
};

/**
 * Function: setBaseUrl
 * 
 * Sets <baseUrl>.
 */
mxUrlConverter.prototype.setBaseUrl = function(value)
{
\tthis.baseUrl = value;
};

/**
 * Function: getBaseDomain
 * 
 * Returns <baseDomain>.
 */
mxUrlConverter.prototype.getBaseDomain = function()
{
\treturn this.baseDomain;
};

/**
 * Function: setBaseDomain
 * 
 * Sets <baseDomain>.
 */
mxUrlConverter.prototype.setBaseDomain = function(value)
{
\tthis.baseDomain = value;
};

/**
 * Function: isRelativeUrl
 * 
 * Returns true if the given URL is relative.
 */
mxUrlConverter.prototype.isRelativeUrl = function(url)
{
\treturn url != null && url.substring(0, 2) != '//' && url.substring(0, 7) != 'http://' &&
\t\turl.substring(0, 8) != 'https://' && url.substring(0, 10) != 'data:image' &&
\t\turl.substring(0, 7) != 'file://';
};

/**
 * Function: convert
 * 
 * Converts the given URL to an absolute URL with protol and domain.
 * Relative URLs are first converted to absolute URLs.
 */
mxUrlConverter.prototype.convert = function(url)
{
\tif (this.isEnabled() && this.isRelativeUrl(url))
\t{
\t\tif (this.getBaseUrl() == null)
\t\t{
\t\t\tthis.updateBaseUrl();
\t\t}
\t\t
\t\tif (url.charAt(0) == '/')
\t\t{
\t\t\turl = this.getBaseDomain() + url;
\t\t}
\t\telse
\t\t{
\t\t\turl = this.getBaseUrl() + url;
\t\t}
\t}
\t
\treturn url;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPanningManager
 *
 * Implements a handler for panning.
 */
function mxPanningManager(graph)
{
\tthis.thread = null;
\tthis.active = false;
\tthis.tdx = 0;
\tthis.tdy = 0;
\tthis.t0x = 0;
\tthis.t0y = 0;
\tthis.dx = 0;
\tthis.dy = 0;
\tthis.scrollbars = false;
\tthis.scrollLeft = 0;
\tthis.scrollTop = 0;
\t
\tthis.mouseListener =
\t{
\t    mouseDown: function(sender, me) { },
\t    mouseMove: function(sender, me) { },
\t    mouseUp: mxUtils.bind(this, function(sender, me)
\t    {
\t    \tif (this.active)
\t    \t{
\t    \t\tthis.stop();
\t    \t}
\t    })
\t};
\t
\tgraph.addMouseListener(this.mouseListener);
\t
\tthis.mouseUpListener = mxUtils.bind(this, function()
\t{
\t    \tif (this.active)
\t    \t{
\t    \t\tthis.stop();
\t    \t}
\t});
\t
\t// Stops scrolling on every mouseup anywhere in the document
\tmxEvent.addListener(document, 'mouseup', this.mouseUpListener);
\t
\tvar createThread = mxUtils.bind(this, function()
\t{
\t    \tthis.scrollbars = mxUtils.hasScrollbars(graph.container);
\t    \tthis.scrollLeft = graph.container.scrollLeft;
\t    \tthis.scrollTop = graph.container.scrollTop;
\t
\t    \treturn window.setInterval(mxUtils.bind(this, function()
\t\t{
\t\t\tthis.tdx -= this.dx;
\t\t\tthis.tdy -= this.dy;

\t\t\tif (this.scrollbars)
\t\t\t{
\t\t\t\tvar left = -graph.container.scrollLeft - Math.ceil(this.dx);
\t\t\t\tvar top = -graph.container.scrollTop - Math.ceil(this.dy);
\t\t\t\tgraph.panGraph(left, top);
\t\t\t\tgraph.panDx = this.scrollLeft - graph.container.scrollLeft;
\t\t\t\tgraph.panDy = this.scrollTop - graph.container.scrollTop;
\t\t\t\tgraph.fireEvent(new mxEventObject(mxEvent.PAN));
\t\t\t\t// TODO: Implement graph.autoExtend
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tgraph.panGraph(this.getDx(), this.getDy());
\t\t\t}
\t\t}), this.delay);
\t});
\t
\tthis.isActive = function()
\t{
\t\treturn active;
\t};
\t
\tthis.getDx = function()
\t{
\t\treturn Math.round(this.tdx);
\t};
\t
\tthis.getDy = function()
\t{
\t\treturn Math.round(this.tdy);
\t};
\t
\tthis.start = function()
\t{
\t\tthis.t0x = graph.view.translate.x;
\t\tthis.t0y = graph.view.translate.y;
\t\tthis.active = true;
\t};
\t
\tthis.panTo = function(x, y, w, h)
\t{
\t\tif (!this.active)
\t\t{
\t\t\tthis.start();
\t\t}
\t\t
    \tthis.scrollLeft = graph.container.scrollLeft;
    \tthis.scrollTop = graph.container.scrollTop;
\t\t
\t\tw = (w != null) ? w : 0;
\t\th = (h != null) ? h : 0;
\t\t
\t\tvar c = graph.container;
\t\tthis.dx = x + w - c.scrollLeft - c.clientWidth;
\t\t
\t\tif (this.dx < 0 && Math.abs(this.dx) < this.border)
\t\t{
\t\t\tthis.dx = this.border + this.dx;
\t\t}
\t\telse if (this.handleMouseOut)
\t\t{
\t\t\tthis.dx = Math.max(this.dx, 0);
\t\t}
\t\telse
\t\t{
\t\t\tthis.dx = 0;
\t\t}
\t\t
\t\tif (this.dx == 0)
\t\t{
\t\t\tthis.dx = x - c.scrollLeft;
\t\t\t
\t\t\tif (this.dx > 0 && this.dx < this.border)
\t\t\t{
\t\t\t\tthis.dx = this.dx - this.border;
\t\t\t}
\t\t\telse if (this.handleMouseOut)
\t\t\t{
\t\t\t\tthis.dx = Math.min(0, this.dx);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.dx = 0;
\t\t\t}
\t\t}
\t\t
\t\tthis.dy = y + h - c.scrollTop - c.clientHeight;

\t\tif (this.dy < 0 && Math.abs(this.dy) < this.border)
\t\t{
\t\t\tthis.dy = this.border + this.dy;
\t\t}
\t\telse if (this.handleMouseOut)
\t\t{
\t\t\tthis.dy = Math.max(this.dy, 0);
\t\t}
\t\telse
\t\t{
\t\t\tthis.dy = 0;
\t\t}
\t\t
\t\tif (this.dy == 0)
\t\t{
\t\t\tthis.dy = y - c.scrollTop;
\t\t\t
\t\t\tif (this.dy > 0 && this.dy < this.border)
\t\t\t{
\t\t\t\tthis.dy = this.dy - this.border;
\t\t\t}
\t\t\telse if (this.handleMouseOut)
\t\t\t{
\t\t\t\tthis.dy = Math.min(0, this.dy);
\t\t\t} 
\t\t\telse
\t\t\t{
\t\t\t\tthis.dy = 0;
\t\t\t}
\t\t}
\t\t
\t\tif (this.dx != 0 || this.dy != 0)
\t\t{
\t\t\tthis.dx *= this.damper;
\t\t\tthis.dy *= this.damper;
\t\t\t
\t\t\tif (this.thread == null)
\t\t\t{
\t\t\t\tthis.thread = createThread();
\t\t\t}
\t\t}
\t\telse if (this.thread != null)
\t\t{
\t\t\twindow.clearInterval(this.thread);
\t\t\tthis.thread = null;
\t\t}
\t};
\t
\tthis.stop = function()
\t{
\t\tif (this.active)
\t\t{
\t\t\tthis.active = false;
\t\t
\t\t\tif (this.thread != null)
\t    \t{
\t\t\t\twindow.clearInterval(this.thread);
\t\t\t\tthis.thread = null;
\t    \t}
\t\t\t
\t\t\tthis.tdx = 0;
\t\t\tthis.tdy = 0;
\t\t\t
\t\t\tif (!this.scrollbars)
\t\t\t{
\t\t\t\tvar px = graph.panDx;
\t\t\t\tvar py = graph.panDy;
\t\t    \t
\t\t    \tif (px != 0 || py != 0)
\t\t    \t{
\t\t    \t\tgraph.panGraph(0, 0);
\t\t\t    \tgraph.view.setTranslate(this.t0x + px / graph.view.scale, this.t0y + py / graph.view.scale);
\t\t    \t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tgraph.panDx = 0;
\t\t\t\tgraph.panDy = 0;
\t\t\t\tgraph.fireEvent(new mxEventObject(mxEvent.PAN));
\t\t\t}
\t\t}
\t};
\t
\tthis.destroy = function()
\t{
\t\tgraph.removeMouseListener(this.mouseListener);
\t\tmxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
\t};
};

/**
 * Variable: damper
 * 
 * Damper value for the panning. Default is 1/6.
 */
mxPanningManager.prototype.damper = 1/6;

/**
 * Variable: delay
 * 
 * Delay in milliseconds for the panning. Default is 10.
 */
mxPanningManager.prototype.delay = 10;

/**
 * Variable: handleMouseOut
 * 
 * Specifies if mouse events outside of the component should be handled. Default is true. 
 */
mxPanningManager.prototype.handleMouseOut = true;

/**
 * Variable: border
 * 
 * Border to handle automatic panning inside the component. Default is 0 (disabled).
 */
mxPanningManager.prototype.border = 0;
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPopupMenu
 * 
 * Basic popup menu. To add a vertical scrollbar to a given submenu, the
 * following code can be used.
 * 
 * (code)
 * var mxPopupMenuShowMenu = mxPopupMenu.prototype.showMenu;
 * mxPopupMenu.prototype.showMenu = function()
 * {
 *   mxPopupMenuShowMenu.apply(this, arguments);
 *   
 *   this.div.style.overflowY = 'auto';
 *   this.div.style.overflowX = 'hidden';
 *   this.div.style.maxHeight = '160px';
 * };
 * (end)
 * 
 * Constructor: mxPopupMenu
 * 
 * Constructs a popupmenu.
 * 
 * Event: mxEvent.SHOW
 *
 * Fires after the menu has been shown in <popup>.
 */
function mxPopupMenu(factoryMethod)
{
\tthis.factoryMethod = factoryMethod;
\t
\tif (factoryMethod != null)
\t{
\t\tthis.init();
\t}
};

/**
 * Extends mxEventSource.
 */
mxPopupMenu.prototype = new mxEventSource();
mxPopupMenu.prototype.constructor = mxPopupMenu;

/**
 * Variable: submenuImage
 * 
 * URL of the image to be used for the submenu icon.
 */
mxPopupMenu.prototype.submenuImage = mxClient.imageBasePath + '/submenu.gif';

/**
 * Variable: zIndex
 * 
 * Specifies the zIndex for the popupmenu and its shadow. Default is 10006.
 */
mxPopupMenu.prototype.zIndex = 10006;

/**
 * Variable: factoryMethod
 * 
 * Function that is used to create the popup menu. The function takes the
 * current panning handler, the <mxCell> under the mouse and the mouse
 * event that triggered the call as arguments.
 */
mxPopupMenu.prototype.factoryMethod = null;

/**
 * Variable: useLeftButtonForPopup
 * 
 * Specifies if popupmenus should be activated by clicking the left mouse
 * button. Default is false.
 */
mxPopupMenu.prototype.useLeftButtonForPopup = false;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxPopupMenu.prototype.enabled = true;

/**
 * Variable: itemCount
 * 
 * Contains the number of times <addItem> has been called for a new menu.
 */
mxPopupMenu.prototype.itemCount = 0;

/**
 * Variable: autoExpand
 * 
 * Specifies if submenus should be expanded on mouseover. Default is false.
 */
mxPopupMenu.prototype.autoExpand = false;

/**
 * Variable: smartSeparators
 * 
 * Specifies if separators should only be added if a menu item follows them.
 * Default is false.
 */
mxPopupMenu.prototype.smartSeparators = false;

/**
 * Variable: labels
 * 
 * Specifies if any labels should be visible. Default is true.
 */
mxPopupMenu.prototype.labels = true;

/**
 * Function: init
 * 
 * Initializes the shapes required for this vertex handler.
 */
mxPopupMenu.prototype.init = function()
{
\t// Adds the inner table
\tthis.table = document.createElement('table');
\tthis.table.className = 'mxPopupMenu';
\t
\tthis.tbody = document.createElement('tbody');
\tthis.table.appendChild(this.tbody);

\t// Adds the outer div
\tthis.div = document.createElement('div');
\tthis.div.className = 'mxPopupMenu';
\tthis.div.style.display = 'inline';
\tthis.div.style.zIndex = this.zIndex;
\tthis.div.appendChild(this.table);

\t// Disables the context menu on the outer div
\tmxEvent.disableContextMenu(this.div);
};

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxPopupMenu.prototype.isEnabled = function()
{
\treturn this.enabled;
};
\t
/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 */
mxPopupMenu.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isPopupTrigger
 * 
 * Returns true if the given event is a popupmenu trigger for the optional
 * given cell.
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> that represents the mouse event.
 */
mxPopupMenu.prototype.isPopupTrigger = function(me)
{
\treturn me.isPopupTrigger() || (this.useLeftButtonForPopup && mxEvent.isLeftMouseButton(me.getEvent()));
};

/**
 * Function: addItem
 * 
 * Adds the given item to the given parent item. If no parent item is specified
 * then the item is added to the top-level menu. The return value may be used
 * as the parent argument, ie. as a submenu item. The return value is the table
 * row that represents the item.
 * 
 * Paramters:
 * 
 * title - String that represents the title of the menu item.
 * image - Optional URL for the image icon.
 * funct - Function associated that takes a mouseup or touchend event.
 * parent - Optional item returned by <addItem>.
 * iconCls - Optional string that represents the CSS class for the image icon.
 * IconsCls is ignored if image is given.
 * enabled - Optional boolean indicating if the item is enabled. Default is true.
 * active - Optional boolean indicating if the menu should implement any event handling.
 * Default is true.
 * noHover - Optional boolean to disable hover state.
 */
mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled, active, noHover)
{
\tparent = parent || this;
\tthis.itemCount++;
\t
\t// Smart separators only added if element contains items
\tif (parent.willAddSeparator)
\t{
\t\tif (parent.containsItems)
\t\t{
\t\t\tthis.addSeparator(parent, true);
\t\t}

\t\tparent.willAddSeparator = false;
\t}

\tparent.containsItems = true;
\tvar tr = document.createElement('tr');
\ttr.className = 'mxPopupMenuItem';
\tvar col1 = document.createElement('td');
\tcol1.className = 'mxPopupMenuIcon';

\t// Adds the given image into the first column
\tif (image != null)
\t{
\t\tvar img = document.createElement('img');
\t\timg.src = image;
\t\tcol1.appendChild(img);
\t}
\telse if (iconCls != null)
\t{
\t\tvar div = document.createElement('div');
\t\tdiv.className = iconCls;
\t\tcol1.appendChild(div);
\t}
\t
\ttr.appendChild(col1);
\t
\tif (this.labels)
\t{
\t\tvar col2 = document.createElement('td');
\t\tcol2.className = 'mxPopupMenuItem' +
\t\t\t((enabled != null && !enabled) ? ' mxDisabled' : '');
\t\t
\t\tmxUtils.write(col2, title);
\t\tcol2.align = 'left';
\t\ttr.appendChild(col2);
\t
\t\tvar col3 = document.createElement('td');
\t\tcol3.className = 'mxPopupMenuItem' +
\t\t\t((enabled != null && !enabled) ? ' mxDisabled' : '');
\t\tcol3.style.paddingRight = '6px';
\t\tcol3.style.textAlign = 'right';
\t\t
\t\ttr.appendChild(col3);
\t\t
\t\tif (parent.div == null)
\t\t{
\t\t\tthis.createSubmenu(parent);
\t\t}
\t}
\t
\tparent.tbody.appendChild(tr);

\tif (active != false && enabled != false)
\t{
\t\tvar currentSelection = null;
\t\t
\t\tmxEvent.addGestureListeners(tr,
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tthis.eventReceiver = tr;
\t\t\t\t
\t\t\t\tif (parent.activeRow != tr && parent.activeRow != parent)
\t\t\t\t{
\t\t\t\t\tif (parent.activeRow != null && parent.activeRow.div.parentNode != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.hideSubmenu(parent);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (tr.div != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.showSubmenu(parent, tr);
\t\t\t\t\t\tparent.activeRow = tr;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Workaround for lost current selection in page because of focus in IE
\t\t\t\tif (document.selection != null && (mxClient.IS_QUIRKS || document.documentMode == 8))
\t\t\t\t{
\t\t\t\t\tcurrentSelection = document.selection.createRange();
\t\t\t\t}
\t\t\t\t
\t\t\t\tmxEvent.consume(evt);
\t\t\t}),
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (parent.activeRow != tr && parent.activeRow != parent)
\t\t\t\t{
\t\t\t\t\tif (parent.activeRow != null && parent.activeRow.div.parentNode != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.hideSubmenu(parent);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (this.autoExpand && tr.div != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.showSubmenu(parent, tr);
\t\t\t\t\t\tparent.activeRow = tr;
\t\t\t\t\t}
\t\t\t\t}
\t\t
\t\t\t\t// Sets hover style because TR in IE doesn't have hover
\t\t\t\tif (!noHover)
\t\t\t\t{
\t\t\t\t\ttr.className = 'mxPopupMenuItemHover';
\t\t\t\t}
\t\t\t}),
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\t// EventReceiver avoids clicks on a submenu item
\t\t\t\t// which has just been shown in the mousedown
\t\t\t\tif (this.eventReceiver == tr)
\t\t\t\t{
\t\t\t\t\tif (parent.activeRow != tr)
\t\t\t\t\t{
\t\t\t\t\t\tthis.hideMenu();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Workaround for lost current selection in page because of focus in IE
\t\t\t\t\tif (currentSelection != null)
\t\t\t\t\t{
\t\t\t\t\t\t// Workaround for \"unspecified error\" in IE8 standards
\t\t\t\t\t\ttry
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrentSelection.select();
\t\t\t\t\t\t}
\t\t\t\t\t\tcatch (e)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t// ignore
\t\t\t\t\t\t}

\t\t\t\t\t\tcurrentSelection = null;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (funct != null)
\t\t\t\t\t{
\t\t\t\t\t\tfunct(evt);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.eventReceiver = null;
\t\t\t\tmxEvent.consume(evt);
\t\t\t})
\t\t);
\t
\t\t// Resets hover style because TR in IE doesn't have hover
\t\tif (!noHover)
\t\t{
\t\t\tmxEvent.addListener(tr, 'mouseout',
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\ttr.className = 'mxPopupMenuItem';
\t\t\t\t})
\t\t\t);
\t\t}
\t}
\t
\treturn tr;
};

/**
 * Adds a checkmark to the given menuitem.
 */
mxPopupMenu.prototype.addCheckmark = function(item, img)
{
\tvar td = item.firstChild.nextSibling;
\ttd.style.backgroundImage = 'url(\\'' + img + '\\')';
\ttd.style.backgroundRepeat = 'no-repeat';
\ttd.style.backgroundPosition = '2px 50%';
};

/**
 * Function: createSubmenu
 * 
 * Creates the nodes required to add submenu items inside the given parent
 * item. This is called in <addItem> if a parent item is used for the first
 * time. This adds various DOM nodes and a <submenuImage> to the parent.
 * 
 * Parameters:
 * 
 * parent - An item returned by <addItem>.
 */
mxPopupMenu.prototype.createSubmenu = function(parent)
{
\tparent.table = document.createElement('table');
\tparent.table.className = 'mxPopupMenu';

\tparent.tbody = document.createElement('tbody');
\tparent.table.appendChild(parent.tbody);

\tparent.div = document.createElement('div');
\tparent.div.className = 'mxPopupMenu';

\tparent.div.style.position = 'absolute';
\tparent.div.style.display = 'inline';
\tparent.div.style.zIndex = this.zIndex;
\t
\tparent.div.appendChild(parent.table);
\t
\tvar img = document.createElement('img');
\timg.setAttribute('src', this.submenuImage);
\t
\t// Last column of the submenu item in the parent menu
\ttd = parent.firstChild.nextSibling.nextSibling;
\ttd.appendChild(img);
};

/**
 * Function: showSubmenu
 * 
 * Shows the submenu inside the given parent row.
 */
mxPopupMenu.prototype.showSubmenu = function(parent, row)
{
\tif (row.div != null)
\t{
\t\trow.div.style.left = (parent.div.offsetLeft +
\t\t\trow.offsetLeft+row.offsetWidth - 1) + 'px';
\t\trow.div.style.top = (parent.div.offsetTop+row.offsetTop) + 'px';
\t\tdocument.body.appendChild(row.div);
\t\t
\t\t// Moves the submenu to the left side if there is no space
\t\tvar left = parseInt(row.div.offsetLeft);
\t\tvar width = parseInt(row.div.offsetWidth);
\t\tvar offset = mxUtils.getDocumentScrollOrigin(document);
\t\t
\t\tvar b = document.body;
\t\tvar d = document.documentElement;
\t\t
\t\tvar right = offset.x + (b.clientWidth || d.clientWidth);
\t\t
\t\tif (left + width > right)
\t\t{
\t\t\trow.div.style.left = Math.max(0, (parent.div.offsetLeft - width + ((mxClient.IS_IE) ? 6 : -6))) + 'px';
\t\t}
\t\t
\t\tmxUtils.fit(row.div);
\t}
};

/**
 * Function: addSeparator
 * 
 * Adds a horizontal separator in the given parent item or the top-level menu
 * if no parent is specified.
 * 
 * Parameters:
 * 
 * parent - Optional item returned by <addItem>.
 * force - Optional boolean to ignore <smartSeparators>. Default is false.
 */
mxPopupMenu.prototype.addSeparator = function(parent, force)
{
\tparent = parent || this;
\t
\tif (this.smartSeparators && !force)
\t{
\t\tparent.willAddSeparator = true;
\t}
\telse if (parent.tbody != null)
\t{
\t\tparent.willAddSeparator = false;
\t\tvar tr = document.createElement('tr');
\t\t
\t\tvar col1 = document.createElement('td');
\t\tcol1.className = 'mxPopupMenuIcon';
\t\tcol1.style.padding = '0 0 0 0px';
\t\t
\t\ttr.appendChild(col1);
\t\t
\t\tvar col2 = document.createElement('td');
\t\tcol2.style.padding = '0 0 0 0px';
\t\tcol2.setAttribute('colSpan', '2');
\t
\t\tvar hr = document.createElement('hr');
\t\thr.setAttribute('size', '1');
\t\tcol2.appendChild(hr);
\t\t
\t\ttr.appendChild(col2);
\t\t
\t\tparent.tbody.appendChild(tr);
\t}
};

/**
 * Function: popup
 * 
 * Shows the popup menu for the given event and cell.
 * 
 * Example:
 * 
 * (code)
 * graph.panningHandler.popup = function(x, y, cell, evt)
 * {
 *   mxUtils.alert('Hello, World!');
 * }
 * (end)
 */
mxPopupMenu.prototype.popup = function(x, y, cell, evt)
{
\tif (this.div != null && this.tbody != null && this.factoryMethod != null)
\t{
\t\tthis.div.style.left = x + 'px';
\t\tthis.div.style.top = y + 'px';
\t\t
\t\t// Removes all child nodes from the existing menu
\t\twhile (this.tbody.firstChild != null)
\t\t{
\t\t\tmxEvent.release(this.tbody.firstChild);
\t\t\tthis.tbody.removeChild(this.tbody.firstChild);
\t\t}
\t\t
\t\tthis.itemCount = 0;
\t\tthis.factoryMethod(this, cell, evt);
\t\t
\t\tif (this.itemCount > 0)
\t\t{
\t\t\tthis.showMenu();
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.SHOW));
\t\t}
\t}
};

/**
 * Function: isMenuShowing
 * 
 * Returns true if the menu is showing.
 */
mxPopupMenu.prototype.isMenuShowing = function()
{
\treturn this.div != null && this.div.parentNode == document.body;
};

/**
 * Function: showMenu
 * 
 * Shows the menu.
 */
mxPopupMenu.prototype.showMenu = function()
{
\t// Disables filter-based shadow in IE9 standards mode
\tif (document.documentMode >= 9)
\t{
\t\tthis.div.style.filter = 'none';
\t}
\t
\t// Fits the div inside the viewport
\tdocument.body.appendChild(this.div);
\tmxUtils.fit(this.div);
};

/**
 * Function: hideMenu
 * 
 * Removes the menu and all submenus.
 */
mxPopupMenu.prototype.hideMenu = function()
{
\tif (this.div != null)
\t{
\t\tif (this.div.parentNode != null)
\t\t{
\t\t\tthis.div.parentNode.removeChild(this.div);
\t\t}
\t\t
\t\tthis.hideSubmenu(this);
\t\tthis.containsItems = false;
\t\tthis.fireEvent(new mxEventObject(mxEvent.HIDE));
\t}
};

/**
 * Function: hideSubmenu
 * 
 * Removes all submenus inside the given parent.
 * 
 * Parameters:
 * 
 * parent - An item returned by <addItem>.
 */
mxPopupMenu.prototype.hideSubmenu = function(parent)
{
\tif (parent.activeRow != null)
\t{
\t\tthis.hideSubmenu(parent.activeRow);
\t\t
\t\tif (parent.activeRow.div.parentNode != null)
\t\t{
\t\t\tparent.activeRow.div.parentNode.removeChild(parent.activeRow.div);
\t\t}
\t\t
\t\tparent.activeRow = null;
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxPopupMenu.prototype.destroy = function()
{
\tif (this.div != null)
\t{
\t\tmxEvent.release(this.div);
\t\t
\t\tif (this.div.parentNode != null)
\t\t{
\t\t\tthis.div.parentNode.removeChild(this.div);
\t\t}
\t\t
\t\tthis.div = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxAutoSaveManager
 * 
 * Manager for automatically saving diagrams. The <save> hook must be
 * implemented.
 * 
 * Example:
 * 
 * (code)
 * var mgr = new mxAutoSaveManager(editor.graph);
 * mgr.save = function()
 * {
 *   mxLog.show();
 *   mxLog.debug('save');
 * };
 * (end)
 * 
 * Constructor: mxAutoSaveManager
 *
 * Constructs a new automatic layout for the given graph.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing graph. 
 */
function mxAutoSaveManager(graph)
{
\t// Notifies the manager of a change
\tthis.changeHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled())
\t\t{
\t\t\tthis.graphModelChanged(evt.getProperty('edit').changes);
\t\t}
\t});

\tthis.setGraph(graph);
};

/**
 * Extends mxEventSource.
 */
mxAutoSaveManager.prototype = new mxEventSource();
mxAutoSaveManager.prototype.constructor = mxAutoSaveManager;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxAutoSaveManager.prototype.graph = null;

/**
 * Variable: autoSaveDelay
 * 
 * Minimum amount of seconds between two consecutive autosaves. Eg. a
 * value of 1 (s) means the graph is not stored more than once per second.
 * Default is 10.
 */
mxAutoSaveManager.prototype.autoSaveDelay = 10;

/**
 * Variable: autoSaveThrottle
 * 
 * Minimum amount of seconds between two consecutive autosaves triggered by
 * more than <autoSaveThreshhold> changes within a timespan of less than
 * <autoSaveDelay> seconds. Eg. a value of 1 (s) means the graph is not
 * stored more than once per second even if there are more than
 * <autoSaveThreshold> changes within that timespan. Default is 2.
 */
mxAutoSaveManager.prototype.autoSaveThrottle = 2;

/**
 * Variable: autoSaveThreshold
 * 
 * Minimum amount of ignored changes before an autosave. Eg. a value of 2
 * means after 2 change of the graph model the autosave will trigger if the
 * condition below is true. Default is 5.
 */
mxAutoSaveManager.prototype.autoSaveThreshold = 5;

/**
 * Variable: ignoredChanges
 * 
 * Counter for ignored changes in autosave.
 */
mxAutoSaveManager.prototype.ignoredChanges = 0;

/**
 * Variable: lastSnapshot
 * 
 * Used for autosaving. See <autosave>.
 */
mxAutoSaveManager.prototype.lastSnapshot = 0;

/**
 * Variable: enabled
 * 
 * Specifies if event handling is enabled. Default is true.
 */
mxAutoSaveManager.prototype.enabled = true;

/**
 * Variable: changeHandler
 * 
 * Holds the function that handles graph model changes.
 */
mxAutoSaveManager.prototype.changeHandler = null;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxAutoSaveManager.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxAutoSaveManager.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: setGraph
 * 
 * Sets the graph that the layouts operate on.
 */
mxAutoSaveManager.prototype.setGraph = function(graph)
{
\tif (this.graph != null)
\t{
\t\tthis.graph.getModel().removeListener(this.changeHandler);
\t}
\t
\tthis.graph = graph;
\t
\tif (this.graph != null)
\t{
\t\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
\t}
};

/**
 * Function: save
 * 
 * Empty hook that is called if the graph should be saved.
 */
mxAutoSaveManager.prototype.save = function()
{
\t// empty
};

/**
 * Function: graphModelChanged
 * 
 * Invoked when the graph model has changed.
 */
mxAutoSaveManager.prototype.graphModelChanged = function(changes)
{
\tvar now = new Date().getTime();
\tvar dt = (now - this.lastSnapshot) / 1000;
\t
\tif (dt > this.autoSaveDelay ||
\t\t(this.ignoredChanges >= this.autoSaveThreshold &&
\t\t dt > this.autoSaveThrottle))
\t{
\t\tthis.save();
\t\tthis.reset();
\t}
\telse
\t{
\t\t// Increments the number of ignored changes
\t\tthis.ignoredChanges++;
\t}
};

/**
 * Function: reset
 * 
 * Resets all counters.
 */
mxAutoSaveManager.prototype.reset = function()
{
\tthis.lastSnapshot = new Date().getTime();
\tthis.ignoredChanges = 0;
};

/**
 * Function: destroy
 * 
 * Removes all handlers from the <graph> and deletes the reference to it.
 */
mxAutoSaveManager.prototype.destroy = function()
{
\tthis.setGraph(null);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 *
 * Class: mxAnimation
 * 
 * Implements a basic animation in JavaScript.
 * 
 * Constructor: mxAnimation
 * 
 * Constructs an animation.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxAnimation(delay)
{
\tthis.delay = (delay != null) ? delay : 20;
};

/**
 * Extends mxEventSource.
 */
mxAnimation.prototype = new mxEventSource();
mxAnimation.prototype.constructor = mxAnimation;

/**
 * Variable: delay
 * 
 * Specifies the delay between the animation steps. Defaul is 30ms.
 */
mxAnimation.prototype.delay = null;

/**
 * Variable: thread
 * 
 * Reference to the thread while the animation is running.
 */
mxAnimation.prototype.thread = null;

/**
 * Function: isRunning
 * 
 * Returns true if the animation is running.
 */
mxAnimation.prototype.isRunning = function()
{
\treturn this.thread != null;
};

/**
 * Function: startAnimation
 *
 * Starts the animation by repeatedly invoking updateAnimation.
 */
mxAnimation.prototype.startAnimation = function()
{
\tif (this.thread == null)
\t{
\t\tthis.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay);
\t}
};

/**
 * Function: updateAnimation
 *
 * Hook for subclassers to implement the animation. Invoke stopAnimation
 * when finished, startAnimation to resume. This is called whenever the
 * timer fires and fires an mxEvent.EXECUTE event with no properties.
 */
mxAnimation.prototype.updateAnimation = function()
{
\tthis.fireEvent(new mxEventObject(mxEvent.EXECUTE));
};

/**
 * Function: stopAnimation
 *
 * Stops the animation by deleting the timer and fires an <mxEvent.DONE>.
 */
mxAnimation.prototype.stopAnimation = function()
{
\tif (this.thread != null)
\t{
\t\twindow.clearInterval(this.thread);
\t\tthis.thread = null;
\t\tthis.fireEvent(new mxEventObject(mxEvent.DONE));
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 *
 * Class: mxMorphing
 * 
 * Implements animation for morphing cells. Here is an example of
 * using this class for animating the result of a layout algorithm:
 * 
 * (code)
 * graph.getModel().beginUpdate();
 * try
 * {
 *   var circleLayout = new mxCircleLayout(graph);
 *   circleLayout.execute(graph.getDefaultParent());
 * }
 * finally
 * {
 *   var morph = new mxMorphing(graph);
 *   morph.addListener(mxEvent.DONE, function()
 *   {
 *     graph.getModel().endUpdate();
 *   });
 *   
 *   morph.startAnimation();
 * }
 * (end)
 * 
 * Constructor: mxMorphing
 * 
 * Constructs an animation.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * steps - Optional number of steps in the morphing animation. Default is 6.
 * ease - Optional easing constant for the animation. Default is 1.5.
 * delay - Optional delay between the animation steps. Passed to <mxAnimation>.
 */
function mxMorphing(graph, steps, ease, delay)
{
\tmxAnimation.call(this, delay);
\tthis.graph = graph;
\tthis.steps = (steps != null) ? steps : 6;
\tthis.ease = (ease != null) ? ease : 1.5;
};

/**
 * Extends mxEventSource.
 */
mxMorphing.prototype = new mxAnimation();
mxMorphing.prototype.constructor = mxMorphing;

/**
 * Variable: graph
 * 
 * Specifies the delay between the animation steps. Defaul is 30ms.
 */
mxMorphing.prototype.graph = null;

/**
 * Variable: steps
 * 
 * Specifies the maximum number of steps for the morphing.
 */
mxMorphing.prototype.steps = null;

/**
 * Variable: step
 * 
 * Contains the current step.
 */
mxMorphing.prototype.step = 0;

/**
 * Variable: ease
 * 
 * Ease-off for movement towards the given vector. Larger values are
 * slower and smoother. Default is 4.
 */
mxMorphing.prototype.ease = null;

/**
 * Variable: cells
 * 
 * Optional array of cells to be animated. If this is not specified
 * then all cells are checked and animated if they have been moved
 * in the current transaction.
 */
mxMorphing.prototype.cells = null;

/**
 * Function: updateAnimation
 *
 * Animation step.
 */
mxMorphing.prototype.updateAnimation = function()
{
\tmxAnimation.prototype.updateAnimation.apply(this, arguments);
\tvar move = new mxCellStatePreview(this.graph);

\tif (this.cells != null)
\t{
\t\t// Animates the given cells individually without recursion
\t\tfor (var i = 0; i < this.cells.length; i++)
\t\t{
\t\t\tthis.animateCell(this.cells[i], move, false);
\t\t}
\t}
\telse
\t{
\t\t// Animates all changed cells by using recursion to find
\t\t// the changed cells but not for the animation itself
\t\tthis.animateCell(this.graph.getModel().getRoot(), move, true);
\t}
\t
\tthis.show(move);
\t
\tif (move.isEmpty() || this.step++ >= this.steps)
\t{
\t\tthis.stopAnimation();
\t}
};

/**
 * Function: show
 *
 * Shows the changes in the given <mxCellStatePreview>.
 */
mxMorphing.prototype.show = function(move)
{
\tmove.show();
};

/**
 * Function: animateCell
 *
 * Animates the given cell state using <mxCellStatePreview.moveState>.
 */
mxMorphing.prototype.animateCell = function(cell, move, recurse)
{
\tvar state = this.graph.getView().getState(cell);
\tvar delta = null;

\tif (state != null)
\t{
\t\t// Moves the animated state from where it will be after the model
\t\t// change by subtracting the given delta vector from that location
\t\tdelta = this.getDelta(state);

\t\tif (this.graph.getModel().isVertex(cell) && (delta.x != 0 || delta.y != 0))
\t\t{
\t\t\tvar translate = this.graph.view.getTranslate();
\t\t\tvar scale = this.graph.view.getScale();
\t\t\t
\t\t\tdelta.x += translate.x * scale;
\t\t\tdelta.y += translate.y * scale;
\t\t\t
\t\t\tmove.moveState(state, -delta.x / this.ease, -delta.y / this.ease);
\t\t}
\t}
\t
\tif (recurse && !this.stopRecursion(state, delta))
\t{
\t\tvar childCount = this.graph.getModel().getChildCount(cell);

\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tthis.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse);
\t\t}
\t}
};

/**
 * Function: stopRecursion
 *
 * Returns true if the animation should not recursively find more
 * deltas for children if the given parent state has been animated.
 */
mxMorphing.prototype.stopRecursion = function(state, delta)
{
\treturn delta != null && (delta.x != 0 || delta.y != 0);
};

/**
 * Function: getDelta
 *
 * Returns the vector between the current rendered state and the future
 * location of the state after the display will be updated.
 */
mxMorphing.prototype.getDelta = function(state)
{
\tvar origin = this.getOriginForCell(state.cell);
\tvar translate = this.graph.getView().getTranslate();
\tvar scale = this.graph.getView().getScale();
\tvar x = state.x / scale - translate.x;
\tvar y = state.y / scale - translate.y;

\treturn new mxPoint((origin.x - x) * scale, (origin.y - y) * scale);
};

/**
 * Function: getOriginForCell
 *
 * Returns the top, left corner of the given cell. TODO: Improve performance
 * by using caching inside this method as the result per cell never changes
 * during the lifecycle of this object.
 */
mxMorphing.prototype.getOriginForCell = function(cell)
{
\tvar result = null;
\t
\tif (cell != null)
\t{
\t\tvar parent = this.graph.getModel().getParent(cell);
\t\tvar geo = this.graph.getCellGeometry(cell);
\t\tresult = this.getOriginForCell(parent);
\t\t
\t\t// TODO: Handle offsets
\t\tif (geo != null)
\t\t{
\t\t\tif (geo.relative)
\t\t\t{
\t\t\t\tvar pgeo = this.graph.getCellGeometry(parent);
\t\t\t\t
\t\t\t\tif (pgeo != null)
\t\t\t\t{
\t\t\t\t\tresult.x += geo.x * pgeo.width;
\t\t\t\t\tresult.y += geo.y * pgeo.height;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.x += geo.x;
\t\t\t\tresult.y += geo.y;
\t\t\t}
\t\t}
\t}
\t
\tif (result == null)
\t{
\t\tvar t = this.graph.view.getTranslate();
\t\tresult = new mxPoint(-t.x, -t.y);
\t}
\t
\treturn result;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxImageBundle
 *
 * Maps from keys to base64 encoded images or file locations. All values must
 * be URLs or use the format data:image/format followed by a comma and the base64
 * encoded image data, eg. \"data:image/gif,XYZ\", where XYZ is the base64 encoded
 * image data.
 * 
 * To add a new image bundle to an existing graph, the following code is used:
 * 
 * (code)
 * var bundle = new mxImageBundle(alt);
 * bundle.putImage('myImage', 'data:image/gif,R0lGODlhEAAQAMIGAAAAAICAAICAgP' +
 *   '//AOzp2O3r2////////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAHACwAAAAA' +
 *   'EAAQAAADTXi63AowynnAMDfjPUDlnAAJhmeBFxAEloliKltWmiYCQvfVr6lBPB1ggxN1hi' +
 *   'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=', fallback);
 * bundle.putImage('mySvgImage', 'data:image/svg+xml,' + encodeURIComponent(
 *   '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\">' +
 *   '<linearGradient id=\"gradient\"><stop offset=\"10%\" stop-color=\"#F00\"/>' +
 *   '<stop offset=\"90%\" stop-color=\"#fcc\"/></linearGradient>' +
 *   '<rect fill=\"url(#gradient)\" width=\"100%\" height=\"100%\"/></svg>'), fallback);
 * graph.addImageBundle(bundle);
 * (end);
 * 
 * Alt is an optional boolean (default is false) that specifies if the value
 * or the fallback should be returned in <getImage>.
 * 
 * The image can then be referenced in any cell style using image=myImage.
 * If you are using mxOutline, you should use the same image bundles in the
 * graph that renders the outline.
 * 
 * The keys for images are resolved in <mxGraph.postProcessCellStyle> and
 * turned into a data URI if the returned value has a short data URI format
 * as specified above.
 * 
 * A typical value for the fallback is a MTHML link as defined in RFC 2557.
 * Note that this format requires a file to be dynamically created on the
 * server-side, or the page that contains the graph to be modified to contain
 * the resources, this can be done by adding a comment that contains the
 * resource in the HEAD section of the page after the title tag.
 * 
 * This type of fallback mechanism should be used in IE6 and IE7. IE8 does
 * support data URIs, but the maximum size is limited to 32 KB, which means
 * all data URIs should be limited to 32 KB.
 */
function mxImageBundle(alt)
{
\tthis.images = [];
\tthis.alt = (alt != null) ? alt : false;
};

/**
 * Variable: images
 * 
 * Maps from keys to images.
 */
mxImageBundle.prototype.images = null;

/**
 * Variable: alt
 * 
 * Specifies if the fallback representation should be returned.
 */
mxImageBundle.prototype.alt = null;

/**
 * Function: putImage
 * 
 * Adds the specified entry to the map. The entry is an object with a value and
 * fallback property as specified in the arguments.
 */
mxImageBundle.prototype.putImage = function(key, value, fallback)
{
\tthis.images[key] = {value: value, fallback: fallback};
};

/**
 * Function: getImage
 * 
 * Returns the value for the given key. This returns the value
 * or fallback, depending on <alt>. The fallback is returned if
 * <alt> is true, the value is returned otherwise.
 */
mxImageBundle.prototype.getImage = function(key)
{
\tvar result = null;
\t
\tif (key != null)
\t{
\t\tvar img = this.images[key];
\t\t
\t\tif (img != null)
\t\t{
\t\t\tresult = (this.alt) ? img.fallback : img.value;
\t\t}
\t}
\t
\treturn result;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxImageExport
 * 
 * Creates a new image export instance to be used with an export canvas. Here
 * is an example that uses this class to create an image via a backend using
 * <mxXmlExportCanvas>.
 * 
 * (code)
 * var xmlDoc = mxUtils.createXmlDocument();
 * var root = xmlDoc.createElement('output');
 * xmlDoc.appendChild(root);
 * 
 * var xmlCanvas = new mxXmlCanvas2D(root);
 * var imgExport = new mxImageExport();
 * imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
 * 
 * var bounds = graph.getGraphBounds();
 * var w = Math.ceil(bounds.x + bounds.width);
 * var h = Math.ceil(bounds.y + bounds.height);
 * 
 * var xml = mxUtils.getXml(root);
 * new mxXmlRequest('export', 'format=png&w=' + w +
 * \t\t'&h=' + h + '&bg=#F9F7ED&xml=' + encodeURIComponent(xml))
 * \t\t.simulate(document, '_blank');
 * (end)
 * 
 * Constructor: mxImageExport
 * 
 * Constructs a new image export.
 */
function mxImageExport() { };

/**
 * Variable: includeOverlays
 * 
 * Specifies if overlays should be included in the export. Default is false.
 */
mxImageExport.prototype.includeOverlays = false;

/**
 * Function: drawState
 * 
 * Draws the given state and all its descendants to the given canvas.
 */
mxImageExport.prototype.drawState = function(state, canvas)
{
\tif (state != null)
\t{
\t\tthis.visitStatesRecursive(state, canvas, mxUtils.bind(this, function()
\t\t{
\t\t\tthis.drawCellState.apply(this, arguments);
\t\t}));
\t\t\t\t
\t\t// Paints the overlays
\t\tif (this.includeOverlays)
\t\t{
\t\t\tthis.visitStatesRecursive(state, canvas, mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tthis.drawOverlays.apply(this, arguments);
\t\t\t}));
\t\t}
\t}
};

/**
 * Function: visitStatesRecursive
 * 
 * Visits the given state and all its descendants to the given canvas recursively.
 */
mxImageExport.prototype.visitStatesRecursive = function(state, canvas, visitor)
{
\tif (state != null)
\t{
\t\tvisitor(state, canvas);
\t\t
\t\tvar graph = state.view.graph;
\t\tvar childCount = graph.model.getChildCount(state.cell);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar childState = graph.view.getState(graph.model.getChildAt(state.cell, i));
\t\t\tthis.visitStatesRecursive(childState, canvas, visitor);
\t\t}
\t}
};

/**
 * Function: getLinkForCellState
 * 
 * Returns the link for the given cell state and canvas. This returns null.
 */
mxImageExport.prototype.getLinkForCellState = function(state, canvas)
{
\treturn null;
};

/**
 * Function: drawCellState
 * 
 * Draws the given state to the given canvas.
 */
mxImageExport.prototype.drawCellState = function(state, canvas)
{
\t// Experimental feature
\tvar link = this.getLinkForCellState(state, canvas);
\t
\tif (link != null)
\t{
\t\tcanvas.setLink(link);
\t}
\t
\t// Paints the shape and text
\tthis.drawShape(state, canvas);
\tthis.drawText(state, canvas);

\tif (link != null)
\t{
\t\tcanvas.setLink(null);
\t}
};

/**
 * Function: drawShape
 * 
 * Draws the shape of the given state.
 */
mxImageExport.prototype.drawShape = function(state, canvas)
{
\tif (state.shape instanceof mxShape && state.shape.checkBounds())
\t{
\t\tcanvas.save();
\t\t
\t\tstate.shape.beforePaint(canvas);
\t\tstate.shape.paint(canvas);
\t\tstate.shape.afterPaint(canvas);
\t\t
\t\tcanvas.restore();
\t}
};

/**
 * Function: drawText
 * 
 * Draws the text of the given state.
 */
mxImageExport.prototype.drawText = function(state, canvas)
{
\tif (state.text != null && state.text.checkBounds())
\t{
\t\tcanvas.save();
\t\t
\t\tstate.text.beforePaint(canvas);
\t\tstate.text.paint(canvas);
\t\tstate.text.afterPaint(canvas);
\t\t
\t\tcanvas.restore();
\t}
};

/**
 * Function: drawOverlays
 * 
 * Draws the overlays for the given state. This is called if <includeOverlays>
 * is true.
 */
mxImageExport.prototype.drawOverlays = function(state, canvas)
{
\tif (state.overlays != null)
\t{
\t\tstate.overlays.visit(function(id, shape)
\t\t{
\t\t\tif (shape instanceof mxShape)
\t\t\t{
\t\t\t\tshape.paint(canvas);
\t\t\t}
\t\t});
\t}
};

/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxAbstractCanvas2D
 *
 * Base class for all canvases. A description of the public API is available in <mxXmlCanvas2D>.
 * All color values of <mxConstants.NONE> will be converted to null in the state.
 * 
 * Constructor: mxAbstractCanvas2D
 *
 * Constructs a new abstract canvas.
 */
function mxAbstractCanvas2D()
{
\t/**
\t * Variable: converter
\t * 
\t * Holds the <mxUrlConverter> to convert image URLs.
\t */
\tthis.converter = this.createUrlConverter();
\t
\tthis.reset();
};

/**
 * Variable: state
 * 
 * Holds the current state.
 */
mxAbstractCanvas2D.prototype.state = null;

/**
 * Variable: states
 * 
 * Stack of states.
 */
mxAbstractCanvas2D.prototype.states = null;

/**
 * Variable: path
 * 
 * Holds the current path as an array.
 */
mxAbstractCanvas2D.prototype.path = null;

/**
 * Variable: rotateHtml
 * 
 * Switch for rotation of HTML. Default is false.
 */
mxAbstractCanvas2D.prototype.rotateHtml = true;

/**
 * Variable: lastX
 * 
 * Holds the last x coordinate.
 */
mxAbstractCanvas2D.prototype.lastX = 0;

/**
 * Variable: lastY
 * 
 * Holds the last y coordinate.
 */
mxAbstractCanvas2D.prototype.lastY = 0;

/**
 * Variable: moveOp
 * 
 * Contains the string used for moving in paths. Default is 'M'.
 */
mxAbstractCanvas2D.prototype.moveOp = 'M';

/**
 * Variable: lineOp
 * 
 * Contains the string used for moving in paths. Default is 'L'.
 */
mxAbstractCanvas2D.prototype.lineOp = 'L';

/**
 * Variable: quadOp
 * 
 * Contains the string used for quadratic paths. Default is 'Q'.
 */
mxAbstractCanvas2D.prototype.quadOp = 'Q';

/**
 * Variable: curveOp
 * 
 * Contains the string used for bezier curves. Default is 'C'.
 */
mxAbstractCanvas2D.prototype.curveOp = 'C';

/**
 * Variable: closeOp
 * 
 * Holds the operator for closing curves. Default is 'Z'.
 */
mxAbstractCanvas2D.prototype.closeOp = 'Z';

/**
 * Variable: pointerEvents
 * 
 * Boolean value that specifies if events should be handled. Default is false.
 */
mxAbstractCanvas2D.prototype.pointerEvents = false;

/**
 * Function: createUrlConverter
 * 
 * Create a new <mxUrlConverter> and returns it.
 */
mxAbstractCanvas2D.prototype.createUrlConverter = function()
{
\treturn new mxUrlConverter();
};

/**
 * Function: reset
 * 
 * Resets the state of this canvas.
 */
mxAbstractCanvas2D.prototype.reset = function()
{
\tthis.state = this.createState();
\tthis.states = [];
};

/**
 * Function: createState
 * 
 * Creates the state of the this canvas.
 */
mxAbstractCanvas2D.prototype.createState = function()
{
\treturn {
\t\tdx: 0,
\t\tdy: 0,
\t\tscale: 1,
\t\talpha: 1,
\t\tfillAlpha: 1,
\t\tstrokeAlpha: 1,
\t\tfillColor: null,
\t\tgradientFillAlpha: 1,
\t\tgradientColor: null,
\t\tgradientAlpha: 1,
\t\tgradientDirection: null,
\t\tstrokeColor: null,
\t\tstrokeWidth: 1,
\t\tdashed: false,
\t\tdashPattern: '3 3',
\t\tfixDash: false,
\t\tlineCap: 'flat',
\t\tlineJoin: 'miter',
\t\tmiterLimit: 10,
\t\tfontColor: '#000000',
\t\tfontBackgroundColor: null,
\t\tfontBorderColor: null,
\t\tfontSize: mxConstants.DEFAULT_FONTSIZE,
\t\tfontFamily: mxConstants.DEFAULT_FONTFAMILY,
\t\tfontStyle: 0,
\t\tshadow: false,
\t\tshadowColor: mxConstants.SHADOWCOLOR,
\t\tshadowAlpha: mxConstants.SHADOW_OPACITY,
\t\tshadowDx: mxConstants.SHADOW_OFFSET_X,
\t\tshadowDy: mxConstants.SHADOW_OFFSET_Y,
\t\trotation: 0,
\t\trotationCx: 0,
\t\trotationCy: 0
\t};
};

/**
 * Function: format
 * 
 * Rounds all numbers to integers.
 */
mxAbstractCanvas2D.prototype.format = function(value)
{
\treturn Math.round(parseFloat(value));
};

/**
 * Function: addOp
 * 
 * Adds the given operation to the path.
 */
mxAbstractCanvas2D.prototype.addOp = function()
{
\tif (this.path != null)
\t{
\t\tthis.path.push(arguments[0]);
\t\t
\t\tif (arguments.length > 2)
\t\t{
\t\t\tvar s = this.state;

\t\t\tfor (var i = 2; i < arguments.length; i += 2)
\t\t\t{
\t\t\t\tthis.lastX = arguments[i - 1];
\t\t\t\tthis.lastY = arguments[i];
\t\t\t\t
\t\t\t\tthis.path.push(this.format((this.lastX + s.dx) * s.scale));
\t\t\t\tthis.path.push(this.format((this.lastY + s.dy) * s.scale));
\t\t\t}
\t\t}
\t}
};

/**
 * Function: rotatePoint
 * 
 * Rotates the given point and returns the result as an <mxPoint>.
 */
mxAbstractCanvas2D.prototype.rotatePoint = function(x, y, theta, cx, cy)
{
\tvar rad = theta * (Math.PI / 180);
\t
\treturn mxUtils.getRotatedPoint(new mxPoint(x, y), Math.cos(rad),
\t\tMath.sin(rad), new mxPoint(cx, cy));
};

/**
 * Function: save
 * 
 * Saves the current state.
 */
mxAbstractCanvas2D.prototype.save = function()
{
\tthis.states.push(this.state);
\tthis.state = mxUtils.clone(this.state);
};

/**
 * Function: restore
 * 
 * Restores the current state.
 */
mxAbstractCanvas2D.prototype.restore = function()
{
\tif (this.states.length > 0)
\t{
\t\tthis.state = this.states.pop();
\t}
};

/**
 * Function: setLink
 * 
 * Sets the current link. Hook for subclassers.
 */
mxAbstractCanvas2D.prototype.setLink = function(link)
{
\t// nop
};

/**
 * Function: scale
 * 
 * Scales the current state.
 */
mxAbstractCanvas2D.prototype.scale = function(value)
{
\tthis.state.scale *= value;
\tthis.state.strokeWidth *= value;
};

/**
 * Function: translate
 * 
 * Translates the current state.
 */
mxAbstractCanvas2D.prototype.translate = function(dx, dy)
{
\tthis.state.dx += dx;
\tthis.state.dy += dy;
};

/**
 * Function: rotate
 * 
 * Rotates the current state.
 */
mxAbstractCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
{
\t// nop
};

/**
 * Function: setAlpha
 * 
 * Sets the current alpha.
 */
mxAbstractCanvas2D.prototype.setAlpha = function(value)
{
\tthis.state.alpha = value;
};

/**
 * Function: setFillAlpha
 * 
 * Sets the current solid fill alpha.
 */
mxAbstractCanvas2D.prototype.setFillAlpha = function(value)
{
\tthis.state.fillAlpha = value;
};

/**
 * Function: setStrokeAlpha
 * 
 * Sets the current stroke alpha.
 */
mxAbstractCanvas2D.prototype.setStrokeAlpha = function(value)
{
\tthis.state.strokeAlpha = value;
};

/**
 * Function: setFillColor
 * 
 * Sets the current fill color.
 */
mxAbstractCanvas2D.prototype.setFillColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.fillColor = value;
\tthis.state.gradientColor = null;
};

/**
 * Function: setGradient
 * 
 * Sets the current gradient.
 */
mxAbstractCanvas2D.prototype.setGradient = function(color1, color2, x, y, w, h, direction, alpha1, alpha2)
{
\tvar s = this.state;
\ts.fillColor = color1;
\ts.gradientFillAlpha = (alpha1 != null) ? alpha1 : 1;
\ts.gradientColor = color2;
\ts.gradientAlpha = (alpha2 != null) ? alpha2 : 1;
\ts.gradientDirection = direction;
};

/**
 * Function: setStrokeColor
 * 
 * Sets the current stroke color.
 */
mxAbstractCanvas2D.prototype.setStrokeColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.strokeColor = value;
};

/**
 * Function: setStrokeWidth
 * 
 * Sets the current stroke width.
 */
mxAbstractCanvas2D.prototype.setStrokeWidth = function(value)
{
\tthis.state.strokeWidth = value;
};

/**
 * Function: setDashed
 * 
 * Enables or disables dashed lines.
 */
mxAbstractCanvas2D.prototype.setDashed = function(value, fixDash)
{
\tthis.state.dashed = value;
\tthis.state.fixDash = fixDash;
};

/**
 * Function: setDashPattern
 * 
 * Sets the current dash pattern.
 */
mxAbstractCanvas2D.prototype.setDashPattern = function(value)
{
\tthis.state.dashPattern = value;
};

/**
 * Function: setLineCap
 * 
 * Sets the current line cap.
 */
mxAbstractCanvas2D.prototype.setLineCap = function(value)
{
\tthis.state.lineCap = value;
};

/**
 * Function: setLineJoin
 * 
 * Sets the current line join.
 */
mxAbstractCanvas2D.prototype.setLineJoin = function(value)
{
\tthis.state.lineJoin = value;
};

/**
 * Function: setMiterLimit
 * 
 * Sets the current miter limit.
 */
mxAbstractCanvas2D.prototype.setMiterLimit = function(value)
{
\tthis.state.miterLimit = value;
};

/**
 * Function: setFontColor
 * 
 * Sets the current font color.
 */
mxAbstractCanvas2D.prototype.setFontColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.fontColor = value;
};

/**
 * Function: setFontBackgroundColor
 * 
 * Sets the current font background color.
 */
mxAbstractCanvas2D.prototype.setFontBackgroundColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.fontBackgroundColor = value;
};

/**
 * Function: setFontBorderColor
 * 
 * Sets the current font border color.
 */
mxAbstractCanvas2D.prototype.setFontBorderColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.fontBorderColor = value;
};

/**
 * Function: setFontSize
 * 
 * Sets the current font size.
 */
mxAbstractCanvas2D.prototype.setFontSize = function(value)
{
\tthis.state.fontSize = parseFloat(value);
};

/**
 * Function: setFontFamily
 * 
 * Sets the current font family.
 */
mxAbstractCanvas2D.prototype.setFontFamily = function(value)
{
\tthis.state.fontFamily = value;
};

/**
 * Function: setFontStyle
 * 
 * Sets the current font style.
 */
mxAbstractCanvas2D.prototype.setFontStyle = function(value)
{
\tif (value == null)
\t{
\t\tvalue = 0;
\t}
\t
\tthis.state.fontStyle = value;
};

/**
 * Function: setShadow
 * 
 * Enables or disables and configures the current shadow.
 */
mxAbstractCanvas2D.prototype.setShadow = function(enabled)
{
\tthis.state.shadow = enabled;
};

/**
 * Function: setShadowColor
 * 
 * Enables or disables and configures the current shadow.
 */
mxAbstractCanvas2D.prototype.setShadowColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tthis.state.shadowColor = value;
};

/**
 * Function: setShadowAlpha
 * 
 * Enables or disables and configures the current shadow.
 */
mxAbstractCanvas2D.prototype.setShadowAlpha = function(value)
{
\tthis.state.shadowAlpha = value;
};

/**
 * Function: setShadowOffset
 * 
 * Enables or disables and configures the current shadow.
 */
mxAbstractCanvas2D.prototype.setShadowOffset = function(dx, dy)
{
\tthis.state.shadowDx = dx;
\tthis.state.shadowDy = dy;
};

/**
 * Function: begin
 * 
 * Starts a new path.
 */
mxAbstractCanvas2D.prototype.begin = function()
{
\tthis.lastX = 0;
\tthis.lastY = 0;
\tthis.path = [];
};

/**
 * Function: moveTo
 * 
 *  Moves the current path the given coordinates.
 */
mxAbstractCanvas2D.prototype.moveTo = function(x, y)
{
\tthis.addOp(this.moveOp, x, y);
};

/**
 * Function: lineTo
 * 
 * Draws a line to the given coordinates. Uses moveTo with the op argument.
 */
mxAbstractCanvas2D.prototype.lineTo = function(x, y)
{
\tthis.addOp(this.lineOp, x, y);
};

/**
 * Function: quadTo
 * 
 * Adds a quadratic curve to the current path.
 */
mxAbstractCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
{
\tthis.addOp(this.quadOp, x1, y1, x2, y2);
};

/**
 * Function: curveTo
 * 
 * Adds a bezier curve to the current path.
 */
mxAbstractCanvas2D.prototype.curveTo = function(x1, y1, x2, y2, x3, y3)
{
\tthis.addOp(this.curveOp, x1, y1, x2, y2, x3, y3);
};

/**
 * Function: arcTo
 * 
 * Adds the given arc to the current path. This is a synthetic operation that
 * is broken down into curves.
 */
mxAbstractCanvas2D.prototype.arcTo = function(rx, ry, angle, largeArcFlag, sweepFlag, x, y)
{
\tvar curves = mxUtils.arcToCurves(this.lastX, this.lastY, rx, ry, angle, largeArcFlag, sweepFlag, x, y);
\t
\tif (curves != null)
\t{
\t\tfor (var i = 0; i < curves.length; i += 6) 
\t\t{
\t\t\tthis.curveTo(curves[i], curves[i + 1], curves[i + 2],
\t\t\t\tcurves[i + 3], curves[i + 4], curves[i + 5]);
\t\t}
\t}
};

/**
 * Function: close
 * 
 * Closes the current path.
 */
mxAbstractCanvas2D.prototype.close = function(x1, y1, x2, y2, x3, y3)
{
\tthis.addOp(this.closeOp);
};

/**
 * Function: end
 * 
 * Empty implementation for backwards compatibility. This will be removed.
 */
mxAbstractCanvas2D.prototype.end = function() { };
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxXmlCanvas2D
 *
 * Base class for all canvases. The following methods make up the public
 * interface of the canvas 2D for all painting in mxGraph:
 * 
 * - <save>, <restore>
 * - <scale>, <translate>, <rotate>
 * - <setAlpha>, <setFillAlpha>, <setStrokeAlpha>, <setFillColor>, <setGradient>,
 *   <setStrokeColor>, <setStrokeWidth>, <setDashed>, <setDashPattern>, <setLineCap>, 
 *   <setLineJoin>, <setMiterLimit>
 * - <setFontColor>, <setFontBackgroundColor>, <setFontBorderColor>, <setFontSize>,
 *   <setFontFamily>, <setFontStyle>
 * - <setShadow>, <setShadowColor>, <setShadowAlpha>, <setShadowOffset>
 * - <rect>, <roundrect>, <ellipse>, <image>, <text>
 * - <begin>, <moveTo>, <lineTo>, <quadTo>, <curveTo>
 * - <stroke>, <fill>, <fillAndStroke>
 * 
 * <mxAbstractCanvas2D.arcTo> is an additional method for drawing paths. This is
 * a synthetic method, meaning that it is turned into a sequence of curves by
 * default. Subclassers may add native support for arcs.
 * 
 * Constructor: mxXmlCanvas2D
 *
 * Constructs a new abstract canvas.
 */
function mxXmlCanvas2D(root)
{
\tmxAbstractCanvas2D.call(this);

\t/**
\t * Variable: root
\t * 
\t * Reference to the container for the SVG content.
\t */
\tthis.root = root;

\t// Writes default settings;
\tthis.writeDefaults();
};

/**
 * Extends mxAbstractCanvas2D
 */
mxUtils.extend(mxXmlCanvas2D, mxAbstractCanvas2D);

/**
 * Variable: textEnabled
 * 
 * Specifies if text output should be enabled. Default is true.
 */
mxXmlCanvas2D.prototype.textEnabled = true;

/**
 * Variable: compressed
 * 
 * Specifies if the output should be compressed by removing redundant calls.
 * Default is true.
 */
mxXmlCanvas2D.prototype.compressed = true;

/**
 * Function: writeDefaults
 * 
 * Writes the rendering defaults to <root>:
 */
mxXmlCanvas2D.prototype.writeDefaults = function()
{
\tvar elem;
\t
\t// Writes font defaults
\telem = this.createElement('fontfamily');
\telem.setAttribute('family', mxConstants.DEFAULT_FONTFAMILY);
\tthis.root.appendChild(elem);
\t
\telem = this.createElement('fontsize');
\telem.setAttribute('size', mxConstants.DEFAULT_FONTSIZE);
\tthis.root.appendChild(elem);
\t
\t// Writes shadow defaults
\telem = this.createElement('shadowcolor');
\telem.setAttribute('color', mxConstants.SHADOWCOLOR);
\tthis.root.appendChild(elem);
\t
\telem = this.createElement('shadowalpha');
\telem.setAttribute('alpha', mxConstants.SHADOW_OPACITY);
\tthis.root.appendChild(elem);
\t
\telem = this.createElement('shadowoffset');
\telem.setAttribute('dx', mxConstants.SHADOW_OFFSET_X);
\telem.setAttribute('dy', mxConstants.SHADOW_OFFSET_Y);
\tthis.root.appendChild(elem);
};

/**
 * Function: format
 * 
 * Returns a formatted number with 2 decimal places.
 */
mxXmlCanvas2D.prototype.format = function(value)
{
\treturn parseFloat(parseFloat(value).toFixed(2));
};

/**
 * Function: createElement
 * 
 * Creates the given element using the owner document of <root>.
 */
mxXmlCanvas2D.prototype.createElement = function(name)
{
\treturn this.root.ownerDocument.createElement(name);
};

/**
 * Function: save
 * 
 * Saves the drawing state.
 */
mxXmlCanvas2D.prototype.save = function()
{
\tif (this.compressed)
\t{
\t\tmxAbstractCanvas2D.prototype.save.apply(this, arguments);
\t}
\t
\tthis.root.appendChild(this.createElement('save'));
};

/**
 * Function: restore
 * 
 * Restores the drawing state.
 */
mxXmlCanvas2D.prototype.restore = function()
{
\tif (this.compressed)
\t{
\t\tmxAbstractCanvas2D.prototype.restore.apply(this, arguments);
\t}
\t
\tthis.root.appendChild(this.createElement('restore'));
};

/**
 * Function: scale
 * 
 * Scales the output.
 * 
 * Parameters:
 * 
 * scale - Number that represents the scale where 1 is equal to 100%.
 */
mxXmlCanvas2D.prototype.scale = function(value)
{
        var elem = this.createElement('scale');
        elem.setAttribute('scale', value);
        this.root.appendChild(elem);
};

/**
 * Function: translate
 * 
 * Translates the output.
 * 
 * Parameters:
 * 
 * dx - Number that specifies the horizontal translation.
 * dy - Number that specifies the vertical translation.
 */
mxXmlCanvas2D.prototype.translate = function(dx, dy)
{
\tvar elem = this.createElement('translate');
\telem.setAttribute('dx', this.format(dx));
\telem.setAttribute('dy', this.format(dy));
\tthis.root.appendChild(elem);
};

/**
 * Function: rotate
 * 
 * Rotates and/or flips the output around a given center. (Note: Due to
 * limitations in VML, the rotation cannot be concatenated.)
 * 
 * Parameters:
 * 
 * theta - Number that represents the angle of the rotation (in degrees).
 * flipH - Boolean indicating if the output should be flipped horizontally.
 * flipV - Boolean indicating if the output should be flipped vertically.
 * cx - Number that represents the x-coordinate of the rotation center.
 * cy - Number that represents the y-coordinate of the rotation center.
 */
mxXmlCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
{
\tvar elem = this.createElement('rotate');
\t
\tif (theta != 0 || flipH || flipV)
\t{
\t\telem.setAttribute('theta', this.format(theta));
\t\telem.setAttribute('flipH', (flipH) ? '1' : '0');
\t\telem.setAttribute('flipV', (flipV) ? '1' : '0');
\t\telem.setAttribute('cx', this.format(cx));
\t\telem.setAttribute('cy', this.format(cy));
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setAlpha
 * 
 * Sets the current alpha.
 * 
 * Parameters:
 * 
 * value - Number that represents the new alpha. Possible values are between
 * 1 (opaque) and 0 (transparent).
 */
mxXmlCanvas2D.prototype.setAlpha = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.alpha == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setAlpha.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('alpha');
\telem.setAttribute('alpha', this.format(value));
\tthis.root.appendChild(elem);
};

/**
 * Function: setFillAlpha
 * 
 * Sets the current fill alpha.
 * 
 * Parameters:
 * 
 * value - Number that represents the new fill alpha. Possible values are between
 * 1 (opaque) and 0 (transparent).
 */
mxXmlCanvas2D.prototype.setFillAlpha = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.fillAlpha == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setFillAlpha.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('fillalpha');
\telem.setAttribute('alpha', this.format(value));
\tthis.root.appendChild(elem);
};

/**
 * Function: setStrokeAlpha
 * 
 * Sets the current stroke alpha.
 * 
 * Parameters:
 * 
 * value - Number that represents the new stroke alpha. Possible values are between
 * 1 (opaque) and 0 (transparent).
 */
mxXmlCanvas2D.prototype.setStrokeAlpha = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.strokeAlpha == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setStrokeAlpha.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('strokealpha');
\telem.setAttribute('alpha', this.format(value));
\tthis.root.appendChild(elem);
};

/**
 * Function: setFillColor
 * 
 * Sets the current fill color.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setFillColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tif (this.compressed)
\t{
\t\tif (this.state.fillColor == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setFillColor.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('fillcolor');
\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\tthis.root.appendChild(elem);
};

/**
 * Function: setGradient
 * 
 * Sets the gradient. Note that the coordinates may be ignored by some implementations.
 * 
 * Parameters:
 * 
 * color1 - Hexadecimal representation of the start color.
 * color2 - Hexadecimal representation of the end color.
 * x - X-coordinate of the gradient region.
 * y - y-coordinate of the gradient region.
 * w - Width of the gradient region.
 * h - Height of the gradient region.
 * direction - One of <mxConstants.DIRECTION_NORTH>, <mxConstants.DIRECTION_EAST>,
 * <mxConstants.DIRECTION_SOUTH> or <mxConstants.DIRECTION_WEST>.
 * alpha1 - Optional alpha of the start color. Default is 1. Possible values
 * are between 1 (opaque) and 0 (transparent).
 * alpha2 - Optional alpha of the end color. Default is 1. Possible values
 * are between 1 (opaque) and 0 (transparent).
 */
mxXmlCanvas2D.prototype.setGradient = function(color1, color2, x, y, w, h, direction, alpha1, alpha2)
{
\tif (color1 != null && color2 != null)
\t{
\t\tmxAbstractCanvas2D.prototype.setGradient.apply(this, arguments);
\t\t
\t\tvar elem = this.createElement('gradient');
\t\telem.setAttribute('c1', color1);
\t\telem.setAttribute('c2', color2);
\t\telem.setAttribute('x', this.format(x));
\t\telem.setAttribute('y', this.format(y));
\t\telem.setAttribute('w', this.format(w));
\t\telem.setAttribute('h', this.format(h));
\t\t
\t\t// Default direction is south
\t\tif (direction != null)
\t\t{
\t\t\telem.setAttribute('direction', direction);
\t\t}
\t\t
\t\tif (alpha1 != null)
\t\t{
\t\t\telem.setAttribute('alpha1', alpha1);
\t\t}
\t\t
\t\tif (alpha2 != null)
\t\t{
\t\t\telem.setAttribute('alpha2', alpha2);
\t\t}
\t\t
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setStrokeColor
 * 
 * Sets the current stroke color.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setStrokeColor = function(value)
{
\tif (value == mxConstants.NONE)
\t{
\t\tvalue = null;
\t}
\t
\tif (this.compressed)
\t{
\t\tif (this.state.strokeColor == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setStrokeColor.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('strokecolor');
\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\tthis.root.appendChild(elem);
};

/**
 * Function: setStrokeWidth
 * 
 * Sets the current stroke width.
 * 
 * Parameters:
 * 
 * value - Numeric representation of the stroke width.
 */
mxXmlCanvas2D.prototype.setStrokeWidth = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.strokeWidth == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setStrokeWidth.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('strokewidth');
\telem.setAttribute('width', this.format(value));
\tthis.root.appendChild(elem);
};

/**
 * Function: setDashed
 * 
 * Enables or disables dashed lines.
 * 
 * Parameters:
 * 
 * value - Boolean that specifies if dashed lines should be enabled.
 * value - Boolean that specifies if the stroke width should be ignored
 * for the dash pattern. Default is false.
 */
mxXmlCanvas2D.prototype.setDashed = function(value, fixDash)
{
\tif (this.compressed)
\t{
\t\tif (this.state.dashed == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setDashed.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('dashed');
\telem.setAttribute('dashed', (value) ? '1' : '0');
\t
\tif (fixDash != null)
\t{
\t\telem.setAttribute('fixDash', (fixDash) ? '1' : '0');
\t}
\t
\tthis.root.appendChild(elem);
};

/**
 * Function: setDashPattern
 * 
 * Sets the current dash pattern. Default is '3 3'.
 * 
 * Parameters:
 * 
 * value - String that represents the dash pattern, which is a sequence of
 * numbers defining the length of the dashes and the length of the spaces
 * between the dashes. The lengths are relative to the line width - a length
 * of 1 is equals to the line width.
 */
mxXmlCanvas2D.prototype.setDashPattern = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.dashPattern == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setDashPattern.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('dashpattern');
\telem.setAttribute('pattern', value);
\tthis.root.appendChild(elem);
};

/**
 * Function: setLineCap
 * 
 * Sets the line cap. Default is 'flat' which corresponds to 'butt' in SVG.
 * 
 * Parameters:
 * 
 * value - String that represents the line cap. Possible values are flat, round
 * and square.
 */
mxXmlCanvas2D.prototype.setLineCap = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.lineCap == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setLineCap.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('linecap');
\telem.setAttribute('cap', value);
\tthis.root.appendChild(elem);
};

/**
 * Function: setLineJoin
 * 
 * Sets the line join. Default is 'miter'.
 * 
 * Parameters:
 * 
 * value - String that represents the line join. Possible values are miter,
 * round and bevel.
 */
mxXmlCanvas2D.prototype.setLineJoin = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.lineJoin == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setLineJoin.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('linejoin');
\telem.setAttribute('join', value);
\tthis.root.appendChild(elem);
};

/**
 * Function: setMiterLimit
 * 
 * Sets the miter limit. Default is 10.
 * 
 * Parameters:
 * 
 * value - Number that represents the miter limit.
 */
mxXmlCanvas2D.prototype.setMiterLimit = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.miterLimit == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setMiterLimit.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('miterlimit');
\telem.setAttribute('limit', value);
\tthis.root.appendChild(elem);
};

/**
 * Function: setFontColor
 * 
 * Sets the current font color. Default is '#000000'.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setFontColor = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (value == mxConstants.NONE)
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontColor == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontColor.apply(this, arguments);
\t\t}
\t\t
\t\tvar elem = this.createElement('fontcolor');
\t\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setFontBackgroundColor
 * 
 * Sets the current font background color.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setFontBackgroundColor = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (value == mxConstants.NONE)
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontBackgroundColor == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontBackgroundColor.apply(this, arguments);
\t\t}

\t\tvar elem = this.createElement('fontbackgroundcolor');
\t\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setFontBorderColor
 * 
 * Sets the current font border color.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setFontBorderColor = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (value == mxConstants.NONE)
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontBorderColor == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontBorderColor.apply(this, arguments);
\t\t}
\t\t
\t\tvar elem = this.createElement('fontbordercolor');
\t\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setFontSize
 * 
 * Sets the current font size. Default is <mxConstants.DEFAULT_FONTSIZE>.
 * 
 * Parameters:
 * 
 * value - Numeric representation of the font size.
 */
mxXmlCanvas2D.prototype.setFontSize = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontSize == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontSize.apply(this, arguments);
\t\t}
\t\t
\t\tvar elem = this.createElement('fontsize');
\t\telem.setAttribute('size', value);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setFontFamily
 * 
 * Sets the current font family. Default is <mxConstants.DEFAULT_FONTFAMILY>.
 * 
 * Parameters:
 * 
 * value - String representation of the font family. This handles the same
 * values as the CSS font-family property.
 */
mxXmlCanvas2D.prototype.setFontFamily = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontFamily == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontFamily.apply(this, arguments);
\t\t}
\t\t
\t\tvar elem = this.createElement('fontfamily');
\t\telem.setAttribute('family', value);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setFontStyle
 * 
 * Sets the current font style.
 * 
 * Parameters:
 * 
 * value - Numeric representation of the font family. This is the sum of the
 * font styles from <mxConstants>.
 */
mxXmlCanvas2D.prototype.setFontStyle = function(value)
{
\tif (this.textEnabled)
\t{
\t\tif (value == null)
\t\t{
\t\t\tvalue = 0;
\t\t}
\t\t
\t\tif (this.compressed)
\t\t{
\t\t\tif (this.state.fontStyle == value)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tmxAbstractCanvas2D.prototype.setFontStyle.apply(this, arguments);
\t\t}
\t\t
\t\tvar elem = this.createElement('fontstyle');
\t\telem.setAttribute('style', value);
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: setShadow
 * 
 * Enables or disables shadows.
 * 
 * Parameters:
 * 
 * value - Boolean that specifies if shadows should be enabled.
 */
mxXmlCanvas2D.prototype.setShadow = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.shadow == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setShadow.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('shadow');
\telem.setAttribute('enabled', (value) ? '1' : '0');
\tthis.root.appendChild(elem);
};

/**
 * Function: setShadowColor
 * 
 * Sets the current shadow color. Default is <mxConstants.SHADOWCOLOR>.
 * 
 * Parameters:
 * 
 * value - Hexadecimal representation of the color or 'none'.
 */
mxXmlCanvas2D.prototype.setShadowColor = function(value)
{
\tif (this.compressed)
\t{
\t\tif (value == mxConstants.NONE)
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\tif (this.state.shadowColor == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setShadowColor.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('shadowcolor');
\telem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
\tthis.root.appendChild(elem);
};

/**
 * Function: setShadowAlpha
 * 
 * Sets the current shadows alpha. Default is <mxConstants.SHADOW_OPACITY>.
 * 
 * Parameters:
 * 
 * value - Number that represents the new alpha. Possible values are between
 * 1 (opaque) and 0 (transparent).
 */
mxXmlCanvas2D.prototype.setShadowAlpha = function(value)
{
\tif (this.compressed)
\t{
\t\tif (this.state.shadowAlpha == value)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setShadowAlpha.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('shadowalpha');
\telem.setAttribute('alpha', value);
\tthis.root.appendChild(elem);
\t
};

/**
 * Function: setShadowOffset
 * 
 * Sets the current shadow offset.
 * 
 * Parameters:
 * 
 * dx - Number that represents the horizontal offset of the shadow.
 * dy - Number that represents the vertical offset of the shadow.
 */
mxXmlCanvas2D.prototype.setShadowOffset = function(dx, dy)
{
\tif (this.compressed)
\t{
\t\tif (this.state.shadowDx == dx && this.state.shadowDy == dy)
\t\t{
\t\t\treturn;
\t\t}
\t\t
\t\tmxAbstractCanvas2D.prototype.setShadowOffset.apply(this, arguments);
\t}
\t
\tvar elem = this.createElement('shadowoffset');
\telem.setAttribute('dx', dx);
\telem.setAttribute('dy', dy);
\tthis.root.appendChild(elem);
\t
};

/**
 * Function: rect
 * 
 * Puts a rectangle into the drawing buffer.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the rectangle.
 * y - Number that represents the y-coordinate of the rectangle.
 * w - Number that represents the width of the rectangle.
 * h - Number that represents the height of the rectangle.
 */
mxXmlCanvas2D.prototype.rect = function(x, y, w, h)
{
\tvar elem = this.createElement('rect');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\telem.setAttribute('w', this.format(w));
\telem.setAttribute('h', this.format(h));
\tthis.root.appendChild(elem);
};

/**
 * Function: roundrect
 * 
 * Puts a rounded rectangle into the drawing buffer.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the rectangle.
 * y - Number that represents the y-coordinate of the rectangle.
 * w - Number that represents the width of the rectangle.
 * h - Number that represents the height of the rectangle.
 * dx - Number that represents the horizontal rounding.
 * dy - Number that represents the vertical rounding.
 */
mxXmlCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
{
\tvar elem = this.createElement('roundrect');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\telem.setAttribute('w', this.format(w));
\telem.setAttribute('h', this.format(h));
\telem.setAttribute('dx', this.format(dx));
\telem.setAttribute('dy', this.format(dy));
\tthis.root.appendChild(elem);
};

/**
 * Function: ellipse
 * 
 * Puts an ellipse into the drawing buffer.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the ellipse.
 * y - Number that represents the y-coordinate of the ellipse.
 * w - Number that represents the width of the ellipse.
 * h - Number that represents the height of the ellipse.
 */
mxXmlCanvas2D.prototype.ellipse = function(x, y, w, h)
{
\tvar elem = this.createElement('ellipse');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\telem.setAttribute('w', this.format(w));
\telem.setAttribute('h', this.format(h));
\tthis.root.appendChild(elem);
};

/**
 * Function: image
 * 
 * Paints an image.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the image.
 * y - Number that represents the y-coordinate of the image.
 * w - Number that represents the width of the image.
 * h - Number that represents the height of the image.
 * src - String that specifies the URL of the image.
 * aspect - Boolean indicating if the aspect of the image should be preserved.
 * flipH - Boolean indicating if the image should be flipped horizontally.
 * flipV - Boolean indicating if the image should be flipped vertically.
 */
mxXmlCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
{
\tsrc = this.converter.convert(src);
\t
\t// LATER: Add option for embedding images as base64.
\tvar elem = this.createElement('image');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\telem.setAttribute('w', this.format(w));
\telem.setAttribute('h', this.format(h));
\telem.setAttribute('src', src);
\telem.setAttribute('aspect', (aspect) ? '1' : '0');
\telem.setAttribute('flipH', (flipH) ? '1' : '0');
\telem.setAttribute('flipV', (flipV) ? '1' : '0');
\tthis.root.appendChild(elem);
};

/**
 * Function: begin
 * 
 * Starts a new path and puts it into the drawing buffer.
 */
mxXmlCanvas2D.prototype.begin = function()
{
\tthis.root.appendChild(this.createElement('begin'));
\tthis.lastX = 0;
\tthis.lastY = 0;
};

/**
 * Function: moveTo
 * 
 * Moves the current path the given point.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the point.
 * y - Number that represents the y-coordinate of the point.
 */
mxXmlCanvas2D.prototype.moveTo = function(x, y)
{
\tvar elem = this.createElement('move');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\tthis.root.appendChild(elem);
\tthis.lastX = x;
\tthis.lastY = y;
};

/**
 * Function: lineTo
 * 
 * Draws a line to the given coordinates.
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the endpoint.
 * y - Number that represents the y-coordinate of the endpoint.
 */
mxXmlCanvas2D.prototype.lineTo = function(x, y)
{
\tvar elem = this.createElement('line');
\telem.setAttribute('x', this.format(x));
\telem.setAttribute('y', this.format(y));
\tthis.root.appendChild(elem);
\tthis.lastX = x;
\tthis.lastY = y;
};

/**
 * Function: quadTo
 * 
 * Adds a quadratic curve to the current path.
 * 
 * Parameters:
 * 
 * x1 - Number that represents the x-coordinate of the control point.
 * y1 - Number that represents the y-coordinate of the control point.
 * x2 - Number that represents the x-coordinate of the endpoint.
 * y2 - Number that represents the y-coordinate of the endpoint.
 */
mxXmlCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
{
\tvar elem = this.createElement('quad');
\telem.setAttribute('x1', this.format(x1));
\telem.setAttribute('y1', this.format(y1));
\telem.setAttribute('x2', this.format(x2));
\telem.setAttribute('y2', this.format(y2));
\tthis.root.appendChild(elem);
\tthis.lastX = x2;
\tthis.lastY = y2;
};

/**
 * Function: curveTo
 * 
 * Adds a bezier curve to the current path.
 * 
 * Parameters:
 * 
 * x1 - Number that represents the x-coordinate of the first control point.
 * y1 - Number that represents the y-coordinate of the first control point.
 * x2 - Number that represents the x-coordinate of the second control point.
 * y2 - Number that represents the y-coordinate of the second control point.
 * x3 - Number that represents the x-coordinate of the endpoint.
 * y3 - Number that represents the y-coordinate of the endpoint.
 */
mxXmlCanvas2D.prototype.curveTo = function(x1, y1, x2, y2, x3, y3)
{
\tvar elem = this.createElement('curve');
\telem.setAttribute('x1', this.format(x1));
\telem.setAttribute('y1', this.format(y1));
\telem.setAttribute('x2', this.format(x2));
\telem.setAttribute('y2', this.format(y2));
\telem.setAttribute('x3', this.format(x3));
\telem.setAttribute('y3', this.format(y3));
\tthis.root.appendChild(elem);
\tthis.lastX = x3;
\tthis.lastY = y3;
};

/**
 * Function: close
 * 
 * Closes the current path.
 */
mxXmlCanvas2D.prototype.close = function()
{
\tthis.root.appendChild(this.createElement('close'));
};

/**
 * Function: text
 * 
 * Paints the given text. Possible values for format are empty string for
 * plain text and html for HTML markup. Background and border color as well
 * as clipping is not available in plain text labels for VML. HTML labels
 * are not available as part of shapes with no foreignObject support in SVG
 * (eg. IE9, IE10).
 * 
 * Parameters:
 * 
 * x - Number that represents the x-coordinate of the text.
 * y - Number that represents the y-coordinate of the text.
 * w - Number that represents the available width for the text or 0 for automatic width.
 * h - Number that represents the available height for the text or 0 for automatic height.
 * str - String that specifies the text to be painted.
 * align - String that represents the horizontal alignment.
 * valign - String that represents the vertical alignment.
 * wrap - Boolean that specifies if word-wrapping is enabled. Requires w > 0.
 * format - Empty string for plain text or 'html' for HTML markup.
 * overflow - Specifies the overflow behaviour of the label. Requires w > 0 and/or h > 0.
 * clip - Boolean that specifies if the label should be clipped. Requires w > 0 and/or h > 0.
 * rotation - Number that specifies the angle of the rotation around the anchor point of the text.
 * dir - Optional string that specifies the text direction. Possible values are rtl and lrt.
 */
mxXmlCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
{
\tif (this.textEnabled && str != null)
\t{
\t\tif (mxUtils.isNode(str))
\t\t{
\t\t\tstr = mxUtils.getOuterHtml(str);
\t\t}
\t\t
\t\tvar elem = this.createElement('text');
\t\telem.setAttribute('x', this.format(x));
\t\telem.setAttribute('y', this.format(y));
\t\telem.setAttribute('w', this.format(w));
\t\telem.setAttribute('h', this.format(h));
\t\telem.setAttribute('str', str);
\t\t
\t\tif (align != null)
\t\t{
\t\t\telem.setAttribute('align', align);
\t\t}
\t\t
\t\tif (valign != null)
\t\t{
\t\t\telem.setAttribute('valign', valign);
\t\t}
\t\t
\t\telem.setAttribute('wrap', (wrap) ? '1' : '0');
\t\t
\t\tif (format == null)
\t\t{
\t\t\tformat = '';
\t\t}
\t\t
\t\telem.setAttribute('format', format);
\t\t
\t\tif (overflow != null)
\t\t{
\t\t\telem.setAttribute('overflow', overflow);
\t\t}
\t\t
\t\tif (clip != null)
\t\t{
\t\t\telem.setAttribute('clip', (clip) ? '1' : '0');
\t\t}
\t\t
\t\tif (rotation != null)
\t\t{
\t\t\telem.setAttribute('rotation', rotation);
\t\t}
\t\t
\t\tif (dir != null)
\t\t{
\t\t\telem.setAttribute('dir', dir);
\t\t}
\t\t
\t\tthis.root.appendChild(elem);
\t}
};

/**
 * Function: stroke
 * 
 * Paints the outline of the current drawing buffer.
 */
mxXmlCanvas2D.prototype.stroke = function()
{
\tthis.root.appendChild(this.createElement('stroke'));
};

/**
 * Function: fill
 * 
 * Fills the current drawing buffer.
 */
mxXmlCanvas2D.prototype.fill = function()
{
\tthis.root.appendChild(this.createElement('fill'));
};

/**
 * Function: fillAndStroke
 * 
 * Fills the current drawing buffer and its outline.
 */
mxXmlCanvas2D.prototype.fillAndStroke = function()
{
\tthis.root.appendChild(this.createElement('fillstroke'));
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSvgCanvas2D
 *
 * Extends <mxAbstractCanvas2D> to implement a canvas for SVG. This canvas writes all
 * calls as SVG output to the given SVG root node.
 * 
 * (code)
 * var svgDoc = mxUtils.createXmlDocument();
 * var root = (svgDoc.createElementNS != null) ?
 * \t\tsvgDoc.createElementNS(mxConstants.NS_SVG, 'svg') : svgDoc.createElement('svg');
 * 
 * if (svgDoc.createElementNS == null)
 * {
 *   root.setAttribute('xmlns', mxConstants.NS_SVG);
 *   root.setAttribute('xmlns:xlink', mxConstants.NS_XLINK);
 * }
 * else
 * {
 *   root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', mxConstants.NS_XLINK);
 * }
 * 
 * var bounds = graph.getGraphBounds();
 * root.setAttribute('width', (bounds.x + bounds.width + 4) + 'px');
 * root.setAttribute('height', (bounds.y + bounds.height + 4) + 'px');
 * root.setAttribute('version', '1.1');
 * 
 * svgDoc.appendChild(root);
 * 
 * var svgCanvas = new mxSvgCanvas2D(root);
 * (end)
 * 
 * A description of the public API is available in <mxXmlCanvas2D>.
 * 
 * To disable anti-aliasing in the output, use the following code.
 * 
 * (code)
 * graph.view.canvas.ownerSVGElement.setAttribute('shape-rendering', 'crispEdges');
 * (end)
 * 
 * Or set the respective attribute in the SVG element directly.
 * 
 * Constructor: mxSvgCanvas2D
 *
 * Constructs a new SVG canvas.
 * 
 * Parameters:
 * 
 * root - SVG container for the output.
 * styleEnabled - Optional boolean that specifies if a style section should be
 * added. The style section sets the default font-size, font-family and
 * stroke-miterlimit globally. Default is false.
 */
function mxSvgCanvas2D(root, styleEnabled)
{
\tmxAbstractCanvas2D.call(this);

\t/**
\t * Variable: root
\t * 
\t * Reference to the container for the SVG content.
\t */
\tthis.root = root;

\t/**
\t * Variable: gradients
\t * 
\t * Local cache of gradients for quick lookups.
\t */
\tthis.gradients = [];

\t/**
\t * Variable: defs
\t * 
\t * Reference to the defs section of the SVG document. Only for export.
\t */
\tthis.defs = null;
\t
\t/**
\t * Variable: styleEnabled
\t * 
\t * Stores the value of styleEnabled passed to the constructor.
\t */
\tthis.styleEnabled = (styleEnabled != null) ? styleEnabled : false;
\t
\tvar svg = null;
\t
\t// Adds optional defs section for export
\tif (root.ownerDocument != document)
\t{
\t\tvar node = root;

\t\t// Finds owner SVG element in XML DOM
\t\twhile (node != null && node.nodeName != 'svg')
\t\t{
\t\t\tnode = node.parentNode;
\t\t}
\t\t
\t\tsvg = node;
\t}

\tif (svg != null)
\t{
\t\t// Tries to get existing defs section
\t\tvar tmp = svg.getElementsByTagName('defs');
\t\t
\t\tif (tmp.length > 0)
\t\t{
\t\t\tthis.defs = svg.getElementsByTagName('defs')[0];
\t\t}
\t\t
\t\t// Adds defs section if none exists
\t\tif (this.defs == null)
\t\t{
\t\t\tthis.defs = this.createElement('defs');
\t\t\t
\t\t\tif (svg.firstChild != null)
\t\t\t{
\t\t\t\tsvg.insertBefore(this.defs, svg.firstChild);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tsvg.appendChild(this.defs);
\t\t\t}
\t\t}

\t\t// Adds stylesheet
\t\tif (this.styleEnabled)
\t\t{
\t\t\tthis.defs.appendChild(this.createStyle());
\t\t}
\t}
};

/**
 * Extends mxAbstractCanvas2D
 */
mxUtils.extend(mxSvgCanvas2D, mxAbstractCanvas2D);

/**
 * Capability check for DOM parser and checks if base tag is used.
 */
(function()
{
\tmxSvgCanvas2D.prototype.useDomParser = !mxClient.IS_IE && typeof DOMParser === 'function' && typeof XMLSerializer === 'function';
\t
\tif (mxSvgCanvas2D.prototype.useDomParser)
\t{
\t\t// Checks using a generic test text if the parsing actually works. This is a workaround
\t\t// for older browsers where the capability check returns true but the parsing fails.
\t\ttry
\t\t{
\t\t\tvar doc = new DOMParser().parseFromString('test text', 'text/html');
\t\t\tmxSvgCanvas2D.prototype.useDomParser = doc != null;
\t\t}
\t\tcatch (e)
\t\t{
\t\t\tmxSvgCanvas2D.prototype.useDomParser = false;
\t\t}
\t}
\t
\t// Activates workaround for gradient ID resolution if base tag is used.
\tmxSvgCanvas2D.prototype.useAbsoluteIds = !mxClient.IS_CHROMEAPP && !mxClient.IS_IE && !mxClient.IS_IE11 &&
\t\t!mxClient.IS_EDGE && document.getElementsByTagName('base').length > 0;
})();

/**
 * Variable: path
 * 
 * Holds the current DOM node.
 */
mxSvgCanvas2D.prototype.node = null;

/**
 * Variable: matchHtmlAlignment
 * 
 * Specifies if plain text output should match the vertical HTML alignment.
 * Defaul is true.
 */
mxSvgCanvas2D.prototype.matchHtmlAlignment = true;

/**
 * Variable: textEnabled
 * 
 * Specifies if text output should be enabled. Default is true.
 */
mxSvgCanvas2D.prototype.textEnabled = true;

/**
 * Variable: foEnabled
 * 
 * Specifies if use of foreignObject for HTML markup is allowed. Default is true.
 */
mxSvgCanvas2D.prototype.foEnabled = true;

/**
 * Variable: foAltText
 * 
 * Specifies the fallback text for unsupported foreignObjects in exported
 * documents. Default is '[Object]'. If this is set to null then no fallback
 * text is added to the exported document.
 */
mxSvgCanvas2D.prototype.foAltText = '[Object]';

/**
 * Variable: foOffset
 * 
 * Offset to be used for foreignObjects.
 */
mxSvgCanvas2D.prototype.foOffset = 0;

/**
 * Variable: textOffset
 * 
 * Offset to be used for text elements.
 */
mxSvgCanvas2D.prototype.textOffset = 0;

/**
 * Variable: imageOffset
 * 
 * Offset to be used for image elements.
 */
mxSvgCanvas2D.prototype.imageOffset = 0;

/**
 * Variable: strokeTolerance
 * 
 * Adds transparent paths for strokes.
 */
mxSvgCanvas2D.prototype.strokeTolerance = 0;

/**
 * Variable: minStrokeWidth
 * 
 * Minimum stroke width for output.
 */
mxSvgCanvas2D.prototype.minStrokeWidth = 1;

/**
 * Variable: refCount
 * 
 * Local counter for references in SVG export.
 */
mxSvgCanvas2D.prototype.refCount = 0;

/**
 * Variable: lineHeightCorrection
 * 
 * Correction factor for <mxConstants.LINE_HEIGHT> in HTML output. Default is 1.
 */
mxSvgCanvas2D.prototype.lineHeightCorrection = 1;

/**
 * Variable: pointerEventsValue
 * 
 * Default value for active pointer events. Default is all.
 */
mxSvgCanvas2D.prototype.pointerEventsValue = 'all';

/**
 * Variable: fontMetricsPadding
 * 
 * Padding to be added for text that is not wrapped to account for differences
 * in font metrics on different platforms in pixels. Default is 10.
 */
mxSvgCanvas2D.prototype.fontMetricsPadding = 10;

/**
 * Variable: cacheOffsetSize
 * 
 * Specifies if offsetWidth and offsetHeight should be cached. Default is true.
 * This is used to speed up repaint of text in <updateText>.
 */
mxSvgCanvas2D.prototype.cacheOffsetSize = true;

/**
 * Function: format
 * 
 * Rounds all numbers to 2 decimal points.
 */
mxSvgCanvas2D.prototype.format = function(value)
{
\treturn parseFloat(parseFloat(value).toFixed(2));
};

/**
 * Function: getBaseUrl
 * 
 * Returns the URL of the page without the hash part. This needs to use href to
 * include any search part with no params (ie question mark alone). This is a
 * workaround for the fact that window.location.search is empty if there is
 * no search string behind the question mark.
 */
mxSvgCanvas2D.prototype.getBaseUrl = function()
{
\tvar href = window.location.href;
\tvar hash = href.lastIndexOf('#');
\t
\tif (hash > 0)
\t{
\t\thref = href.substring(0, hash);
\t}
\t
\treturn href;
};

/**
 * Function: reset
 * 
 * Returns any offsets for rendering pixels.
 */
mxSvgCanvas2D.prototype.reset = function()
{
\tmxAbstractCanvas2D.prototype.reset.apply(this, arguments);
\tthis.gradients = [];
};

/**
 * Function: createStyle
 * 
 * Creates the optional style section.
 */
mxSvgCanvas2D.prototype.createStyle = function(x)
{
\tvar style = this.createElement('style');
\tstyle.setAttribute('type', 'text/css');
\tmxUtils.write(style, 'svg{font-family:' + mxConstants.DEFAULT_FONTFAMILY +
\t\t\t';font-size:' + mxConstants.DEFAULT_FONTSIZE +
\t\t\t';fill:none;stroke-miterlimit:10}');
\t
\treturn style;
};

/**
 * Function: createElement
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.createElement = function(tagName, namespace)
{
\tif (this.root.ownerDocument.createElementNS != null)
\t{
\t\treturn this.root.ownerDocument.createElementNS(namespace || mxConstants.NS_SVG, tagName);
\t}
\telse
\t{
\t\tvar elt = this.root.ownerDocument.createElement(tagName);
\t\t
\t\tif (namespace != null)
\t\t{
\t\t\telt.setAttribute('xmlns', namespace);
\t\t}
\t\t
\t\treturn elt;
\t}
};

/**
 * Function: getAlternateText
 * 
 * Returns the alternate text string for the given foreignObject.
 */
mxSvgCanvas2D.prototype.getAlternateText = function(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation)
{
\treturn (str != null) ? this.foAltText : null;
};

/**
 * Function: getAlternateContent
 * 
 * Returns the alternate content for the given foreignObject.
 */
mxSvgCanvas2D.prototype.createAlternateContent = function(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation)
{
\tvar text = this.getAlternateText(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation);
\tvar s = this.state;

\tif (text != null && s.fontSize > 0)
\t{
\t\tvar dy = (valign == mxConstants.ALIGN_TOP) ? 1 :
\t\t\t(valign == mxConstants.ALIGN_BOTTOM) ? 0 : 0.3;
\t\tvar anchor = (align == mxConstants.ALIGN_RIGHT) ? 'end' :
\t\t\t(align == mxConstants.ALIGN_LEFT) ? 'start' :
\t\t\t'middle';
\t
\t\tvar alt = this.createElement('text');
\t\talt.setAttribute('x', Math.round(x + s.dx));
\t\talt.setAttribute('y', Math.round(y + s.dy + dy * s.fontSize));
\t\talt.setAttribute('fill', s.fontColor || 'black');
\t\talt.setAttribute('font-family', s.fontFamily);
\t\talt.setAttribute('font-size', Math.round(s.fontSize) + 'px');

\t\t// Text-anchor start is default in SVG
\t\tif (anchor != 'start')
\t\t{
\t\t\talt.setAttribute('text-anchor', anchor);
\t\t}
\t\t
\t\tif ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t\t{
\t\t\talt.setAttribute('font-weight', 'bold');
\t\t}
\t\t
\t\tif ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t\t{
\t\t\talt.setAttribute('font-style', 'italic');
\t\t}
\t\t
\t\tvar txtDecor = [];
\t\t
\t\tif ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t\t{
\t\t\ttxtDecor.push('underline');
\t\t}
\t\t
\t\tif ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t\t{
\t\t\ttxtDecor.push('line-through');
\t\t}
\t\t
\t\tif (txtDecor.length > 0)
\t\t{
\t\t\talt.setAttribute('text-decoration', txtDecor.join(' '));
\t\t}
\t\t
\t\tmxUtils.write(alt, text);
\t\t
\t\treturn alt;
\t}
\telse
\t{
\t\treturn null;
\t}
};

/**
 * Function: createGradientId
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.createGradientId = function(start, end, alpha1, alpha2, direction)
{
\t// Removes illegal characters from gradient ID
\tif (start.charAt(0) == '#')
\t{
\t\tstart = start.substring(1);
\t}
\t
\tif (end.charAt(0) == '#')
\t{
\t\tend = end.substring(1);
\t}
\t
\t// Workaround for gradient IDs not working in Safari 5 / Chrome 6
\t// if they contain uppercase characters
\tstart = start.toLowerCase() + '-' + alpha1;
\tend = end.toLowerCase() + '-' + alpha2;

\t// Wrong gradient directions possible?
\tvar dir = null;
\t
\tif (direction == null || direction == mxConstants.DIRECTION_SOUTH)
\t{
\t\tdir = 's';
\t}
\telse if (direction == mxConstants.DIRECTION_EAST)
\t{
\t\tdir = 'e';
\t}
\telse
\t{
\t\tvar tmp = start;
\t\tstart = end;
\t\tend = tmp;
\t\t
\t\tif (direction == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\tdir = 's';
\t\t}
\t\telse if (direction == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tdir = 'e';
\t\t}
\t}
\t
\treturn 'mx-gradient-' + start + '-' + end + '-' + dir;
};

/**
 * Function: getSvgGradient
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.getSvgGradient = function(start, end, alpha1, alpha2, direction)
{
\tvar id = this.createGradientId(start, end, alpha1, alpha2, direction);
\tvar gradient = this.gradients[id];
\t
\tif (gradient == null)
\t{
\t\tvar svg = this.root.ownerSVGElement;

\t\tvar counter = 0;
\t\tvar tmpId = id + '-' + counter;

\t\tif (svg != null)
\t\t{
\t\t\tgradient = svg.ownerDocument.getElementById(tmpId);
\t\t\t
\t\t\twhile (gradient != null && gradient.ownerSVGElement != svg)
\t\t\t{
\t\t\t\ttmpId = id + '-' + counter++;
\t\t\t\tgradient = svg.ownerDocument.getElementById(tmpId);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Uses shorter IDs for export
\t\t\ttmpId = 'id' + (++this.refCount);
\t\t}
\t\t
\t\tif (gradient == null)
\t\t{
\t\t\tgradient = this.createSvgGradient(start, end, alpha1, alpha2, direction);
\t\t\tgradient.setAttribute('id', tmpId);
\t\t\t
\t\t\tif (this.defs != null)
\t\t\t{
\t\t\t\tthis.defs.appendChild(gradient);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tsvg.appendChild(gradient);
\t\t\t}
\t\t}

\t\tthis.gradients[id] = gradient;
\t}

\treturn gradient.getAttribute('id');
};

/**
 * Function: createSvgGradient
 * 
 * Creates the given SVG gradient.
 */
mxSvgCanvas2D.prototype.createSvgGradient = function(start, end, alpha1, alpha2, direction)
{
\tvar gradient = this.createElement('linearGradient');
\tgradient.setAttribute('x1', '0%');
\tgradient.setAttribute('y1', '0%');
\tgradient.setAttribute('x2', '0%');
\tgradient.setAttribute('y2', '0%');
\t
\tif (direction == null || direction == mxConstants.DIRECTION_SOUTH)
\t{
\t\tgradient.setAttribute('y2', '100%');
\t}
\telse if (direction == mxConstants.DIRECTION_EAST)
\t{
\t\tgradient.setAttribute('x2', '100%');
\t}
\telse if (direction == mxConstants.DIRECTION_NORTH)
\t{
\t\tgradient.setAttribute('y1', '100%');
\t}
\telse if (direction == mxConstants.DIRECTION_WEST)
\t{
\t\tgradient.setAttribute('x1', '100%');
\t}
\t
\tvar op = (alpha1 < 1) ? ';stop-opacity:' + alpha1 : '';
\t
\tvar stop = this.createElement('stop');
\tstop.setAttribute('offset', '0%');
\tstop.setAttribute('style', 'stop-color:' + start + op);
\tgradient.appendChild(stop);
\t
\top = (alpha2 < 1) ? ';stop-opacity:' + alpha2 : '';
\t
\tstop = this.createElement('stop');
\tstop.setAttribute('offset', '100%');
\tstop.setAttribute('style', 'stop-color:' + end + op);
\tgradient.appendChild(stop);
\t
\treturn gradient;
};

/**
 * Function: addNode
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.addNode = function(filled, stroked)
{
\tvar node = this.node;
\tvar s = this.state;

\tif (node != null)
\t{
\t\tif (node.nodeName == 'path')
\t\t{
\t\t\t// Checks if the path is not empty
\t\t\tif (this.path != null && this.path.length > 0)
\t\t\t{
\t\t\t\tnode.setAttribute('d', this.path.join(' '));
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t}

\t\tif (filled && s.fillColor != null)
\t\t{
\t\t\tthis.updateFill();
\t\t}
\t\telse if (!this.styleEnabled)
\t\t{
\t\t\t// Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=814952
\t\t\tif (node.nodeName == 'ellipse' && mxClient.IS_FF)
\t\t\t{
\t\t\t\tnode.setAttribute('fill', 'transparent');
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tnode.setAttribute('fill', 'none');
\t\t\t}
\t\t\t
\t\t\t// Sets the actual filled state for stroke tolerance
\t\t\tfilled = false;
\t\t}
\t\t
\t\tif (stroked && s.strokeColor != null)
\t\t{
\t\t\tthis.updateStroke();
\t\t}
\t\telse if (!this.styleEnabled)
\t\t{
\t\t\tnode.setAttribute('stroke', 'none');
\t\t}
\t\t
\t\tif (s.transform != null && s.transform.length > 0)
\t\t{
\t\t\tnode.setAttribute('transform', s.transform);
\t\t}
\t\t
\t\tif (s.shadow)
\t\t{
\t\t\tthis.root.appendChild(this.createShadow(node));
\t\t}
\t
\t\t// Adds stroke tolerance
\t\tif (this.strokeTolerance > 0 && !filled)
\t\t{
\t\t\tthis.root.appendChild(this.createTolerance(node));
\t\t}

\t\t// Adds pointer events
\t\tif (this.pointerEvents)
\t\t{
\t\t\tnode.setAttribute('pointer-events', this.pointerEventsValue);
\t\t}
\t\t// Enables clicks for nodes inside a link element
\t\telse if (!this.pointerEvents && this.originalRoot == null)
\t\t{
\t\t\tnode.setAttribute('pointer-events', 'none');
\t\t}
\t\t
\t\t// Removes invisible nodes from output if they don't handle events
\t\tif ((node.nodeName != 'rect' && node.nodeName != 'path' && node.nodeName != 'ellipse') ||
\t\t\t(node.getAttribute('fill') != 'none' && node.getAttribute('fill') != 'transparent') ||
\t\t\tnode.getAttribute('stroke') != 'none' || node.getAttribute('pointer-events') != 'none')
\t\t{
\t\t\t// LATER: Update existing DOM for performance\t\t
\t\t\tthis.root.appendChild(node);
\t\t}
\t\t
\t\tthis.node = null;
\t}
};

/**
 * Function: updateFill
 * 
 * Transfers the stroke attributes from <state> to <node>.
 */
mxSvgCanvas2D.prototype.updateFill = function()
{
\tvar s = this.state;
\t
\tif (s.alpha < 1 || s.fillAlpha < 1)
\t{
\t\tthis.node.setAttribute('fill-opacity', s.alpha * s.fillAlpha);
\t}
\t
\tif (s.fillColor != null)
\t{
\t\tif (s.gradientColor != null)
\t\t{
\t\t\tvar id = this.getSvgGradient(String(s.fillColor), String(s.gradientColor),
\t\t\t\ts.gradientFillAlpha, s.gradientAlpha, s.gradientDirection);
\t\t\t
\t\t\tif (this.root.ownerDocument == document && this.useAbsoluteIds)
\t\t\t{
\t\t\t\t// Workaround for no fill with base tag in page (escape brackets)
\t\t\t\tvar base = this.getBaseUrl().replace(/([\\(\\)])/g, '\\\\\$1');
\t\t\t\tthis.node.setAttribute('fill', 'url(' + base + '#' + id + ')');
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.node.setAttribute('fill', 'url(#' + id + ')');
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tthis.node.setAttribute('fill', String(s.fillColor).toLowerCase());
\t\t}
\t}
};

/**
 * Function: getCurrentStrokeWidth
 * 
 * Returns the current stroke width (>= 1), ie. max(1, this.format(this.state.strokeWidth * this.state.scale)).
 */
mxSvgCanvas2D.prototype.getCurrentStrokeWidth = function()
{
\treturn Math.max(this.minStrokeWidth, Math.max(0.01, this.format(this.state.strokeWidth * this.state.scale)));
};

/**
 * Function: updateStroke
 * 
 * Transfers the stroke attributes from <state> to <node>.
 */
mxSvgCanvas2D.prototype.updateStroke = function()
{
\tvar s = this.state;

\tthis.node.setAttribute('stroke', String(s.strokeColor).toLowerCase());
\t
\tif (s.alpha < 1 || s.strokeAlpha < 1)
\t{
\t\tthis.node.setAttribute('stroke-opacity', s.alpha * s.strokeAlpha);
\t}
\t
\tvar sw = this.getCurrentStrokeWidth();
\t
\tif (sw != 1)
\t{
\t\tthis.node.setAttribute('stroke-width', sw);
\t}
\t
\tif (this.node.nodeName == 'path')
\t{
\t\tthis.updateStrokeAttributes();
\t}
\t
\tif (s.dashed)
\t{
\t\tthis.node.setAttribute('stroke-dasharray', this.createDashPattern(
\t\t\t((s.fixDash) ? 1 : s.strokeWidth) * s.scale));
\t}
};

/**
 * Function: updateStrokeAttributes
 * 
 * Transfers the stroke attributes from <state> to <node>.
 */
mxSvgCanvas2D.prototype.updateStrokeAttributes = function()
{
\tvar s = this.state;
\t
\t// Linejoin miter is default in SVG
\tif (s.lineJoin != null && s.lineJoin != 'miter')
\t{
\t\tthis.node.setAttribute('stroke-linejoin', s.lineJoin);
\t}
\t
\tif (s.lineCap != null)
\t{
\t\t// flat is called butt in SVG
\t\tvar value = s.lineCap;
\t\t
\t\tif (value == 'flat')
\t\t{
\t\t\tvalue = 'butt';
\t\t}
\t\t
\t\t// Linecap butt is default in SVG
\t\tif (value != 'butt')
\t\t{
\t\t\tthis.node.setAttribute('stroke-linecap', value);
\t\t}
\t}
\t
\t// Miterlimit 10 is default in our document
\tif (s.miterLimit != null && (!this.styleEnabled || s.miterLimit != 10))
\t{
\t\tthis.node.setAttribute('stroke-miterlimit', s.miterLimit);
\t}
};

/**
 * Function: createDashPattern
 * 
 * Creates the SVG dash pattern for the given state.
 */
mxSvgCanvas2D.prototype.createDashPattern = function(scale)
{
\tvar pat = [];
\t
\tif (typeof(this.state.dashPattern) === 'string')
\t{
\t\tvar dash = this.state.dashPattern.split(' ');
\t\t
\t\tif (dash.length > 0)
\t\t{
\t\t\tfor (var i = 0; i < dash.length; i++)
\t\t\t{
\t\t\t\tpat[i] = Number(dash[i]) * scale;
\t\t\t}
\t\t}
\t}
\t
\treturn pat.join(' ');
};

/**
 * Function: createTolerance
 * 
 * Creates a hit detection tolerance shape for the given node.
 */
mxSvgCanvas2D.prototype.createTolerance = function(node)
{
\tvar tol = node.cloneNode(true);
\tvar sw = parseFloat(tol.getAttribute('stroke-width') || 1) + this.strokeTolerance;
\ttol.setAttribute('pointer-events', 'stroke');
\ttol.setAttribute('visibility', 'hidden');
\ttol.removeAttribute('stroke-dasharray');
\ttol.setAttribute('stroke-width', sw);
\ttol.setAttribute('fill', 'none');
\t
\t// Workaround for Opera ignoring the visiblity attribute above while
\t// other browsers need a stroke color to perform the hit-detection but
\t// do not ignore the visibility attribute. Side-effect is that Opera's
\t// hit detection for horizontal/vertical edges seems to ignore the tol.
\ttol.setAttribute('stroke', (mxClient.IS_OT) ? 'none' : 'white');
\t
\treturn tol;
};

/**
 * Function: createShadow
 * 
 * Creates a shadow for the given node.
 */
mxSvgCanvas2D.prototype.createShadow = function(node)
{
\tvar shadow = node.cloneNode(true);
\tvar s = this.state;

\t// Firefox uses transparent for no fill in ellipses
\tif (shadow.getAttribute('fill') != 'none' && (!mxClient.IS_FF || shadow.getAttribute('fill') != 'transparent'))
\t{
\t\tshadow.setAttribute('fill', s.shadowColor);
\t}
\t
\tif (shadow.getAttribute('stroke') != 'none')
\t{
\t\tshadow.setAttribute('stroke', s.shadowColor);
\t}

\tshadow.setAttribute('transform', 'translate(' + this.format(s.shadowDx * s.scale) +
\t\t',' + this.format(s.shadowDy * s.scale) + ')' + (s.transform || ''));
\tshadow.setAttribute('opacity', s.shadowAlpha);
\t
\treturn shadow;
};

/**
 * Function: setLink
 * 
 * Experimental implementation for hyperlinks.
 */
mxSvgCanvas2D.prototype.setLink = function(link)
{
\tif (link == null)
\t{
\t\tthis.root = this.originalRoot;
\t}
\telse
\t{
\t\tthis.originalRoot = this.root;
\t\t
\t\tvar node = this.createElement('a');
\t\t
\t\t// Workaround for implicit namespace handling in HTML5 export, IE adds NS1 namespace so use code below
\t\t// in all IE versions except quirks mode. KNOWN: Adds xlink namespace to each image tag in output.
\t\tif (node.setAttributeNS == null || (this.root.ownerDocument != document && document.documentMode == null))
\t\t{
\t\t\tnode.setAttribute('xlink:href', link);
\t\t}
\t\telse
\t\t{
\t\t\tnode.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', link);
\t\t}
\t\t
\t\tthis.root.appendChild(node);
\t\tthis.root = node;
\t}
};

/**
 * Function: rotate
 * 
 * Sets the rotation of the canvas. Note that rotation cannot be concatenated.
 */
mxSvgCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
{
\tif (theta != 0 || flipH || flipV)
\t{
\t\tvar s = this.state;
\t\tcx += s.dx;
\t\tcy += s.dy;
\t
\t\tcx *= s.scale;
\t\tcy *= s.scale;

\t\ts.transform = s.transform || '';
\t\t
\t\t// This implementation uses custom scale/translate and built-in rotation
\t\t// Rotation state is part of the AffineTransform in state.transform
\t\tif (flipH && flipV)
\t\t{
\t\t\ttheta += 180;
\t\t}
\t\telse if (flipH != flipV)
\t\t{
\t\t\tvar tx = (flipH) ? cx : 0;
\t\t\tvar sx = (flipH) ? -1 : 1;
\t
\t\t\tvar ty = (flipV) ? cy : 0;
\t\t\tvar sy = (flipV) ? -1 : 1;

\t\t\ts.transform += 'translate(' + this.format(tx) + ',' + this.format(ty) + ')' +
\t\t\t\t'scale(' + this.format(sx) + ',' + this.format(sy) + ')' +
\t\t\t\t'translate(' + this.format(-tx) + ',' + this.format(-ty) + ')';
\t\t}
\t\t
\t\tif (flipH ? !flipV : flipV)
\t\t{
\t\t\ttheta *= -1;
\t\t}
\t\t
\t\tif (theta != 0)
\t\t{
\t\t\ts.transform += 'rotate(' + this.format(theta) + ',' + this.format(cx) + ',' + this.format(cy) + ')';
\t\t}
\t\t
\t\ts.rotation = s.rotation + theta;
\t\ts.rotationCx = cx;
\t\ts.rotationCy = cy;
\t}
};

/**
 * Function: begin
 * 
 * Extends superclass to create path.
 */
mxSvgCanvas2D.prototype.begin = function()
{
\tmxAbstractCanvas2D.prototype.begin.apply(this, arguments);
\tthis.node = this.createElement('path');
};

/**
 * Function: rect
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.rect = function(x, y, w, h)
{
\tvar s = this.state;
\tvar n = this.createElement('rect');
\tn.setAttribute('x', this.format((x + s.dx) * s.scale));
\tn.setAttribute('y', this.format((y + s.dy) * s.scale));
\tn.setAttribute('width', this.format(w * s.scale));
\tn.setAttribute('height', this.format(h * s.scale));
\t
\tthis.node = n;
};

/**
 * Function: roundrect
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
{
\tthis.rect(x, y, w, h);
\t
\tif (dx > 0)
\t{
\t\tthis.node.setAttribute('rx', this.format(dx * this.state.scale));
\t}
\t
\tif (dy > 0)
\t{
\t\tthis.node.setAttribute('ry', this.format(dy * this.state.scale));
\t}
};

/**
 * Function: ellipse
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.ellipse = function(x, y, w, h)
{
\tvar s = this.state;
\tvar n = this.createElement('ellipse');
\t// No rounding for consistent output with 1.x
\tn.setAttribute('cx', this.format((x + w / 2 + s.dx) * s.scale));
\tn.setAttribute('cy', this.format((y + h / 2 + s.dy) * s.scale));
\tn.setAttribute('rx', w / 2 * s.scale);
\tn.setAttribute('ry', h / 2 * s.scale);
\tthis.node = n;
};

/**
 * Function: image
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
{
\tsrc = this.converter.convert(src);
\t
\t// LATER: Add option for embedding images as base64.
\taspect = (aspect != null) ? aspect : true;
\tflipH = (flipH != null) ? flipH : false;
\tflipV = (flipV != null) ? flipV : false;
\t
\tvar s = this.state;
\tx += s.dx;
\ty += s.dy;
\t
\tvar node = this.createElement('image');
\tnode.setAttribute('x', this.format(x * s.scale) + this.imageOffset);
\tnode.setAttribute('y', this.format(y * s.scale) + this.imageOffset);
\tnode.setAttribute('width', this.format(w * s.scale));
\tnode.setAttribute('height', this.format(h * s.scale));
\t
\t// Workaround for missing namespace support
\tif (node.setAttributeNS == null)
\t{
\t\tnode.setAttribute('xlink:href', src);
\t}
\telse
\t{
\t\tnode.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', src);
\t}
\t
\tif (!aspect)
\t{
\t\tnode.setAttribute('preserveAspectRatio', 'none');
\t}

\tif (s.alpha < 1 || s.fillAlpha < 1)
\t{
\t\tnode.setAttribute('opacity', s.alpha * s.fillAlpha);
\t}
\t
\tvar tr = this.state.transform || '';
\t
\tif (flipH || flipV)
\t{
\t\tvar sx = 1;
\t\tvar sy = 1;
\t\tvar dx = 0;
\t\tvar dy = 0;
\t\t
\t\tif (flipH)
\t\t{
\t\t\tsx = -1;
\t\t\tdx = -w - 2 * x;
\t\t}
\t\t
\t\tif (flipV)
\t\t{
\t\t\tsy = -1;
\t\t\tdy = -h - 2 * y;
\t\t}
\t\t
\t\t// Adds image tansformation to existing transform
\t\ttr += 'scale(' + sx + ',' + sy + ')translate(' + (dx * s.scale) + ',' + (dy * s.scale) + ')';
\t}

\tif (tr.length > 0)
\t{
\t\tnode.setAttribute('transform', tr);
\t}
\t
\tif (!this.pointerEvents)
\t{
\t\tnode.setAttribute('pointer-events', 'none');
\t}
\t
\tthis.root.appendChild(node);
};

/**
 * Function: convertHtml
 * 
 * Converts the given HTML string to XHTML.
 */
mxSvgCanvas2D.prototype.convertHtml = function(val)
{
\tif (this.useDomParser)
\t{
\t\tvar doc = new DOMParser().parseFromString(val, 'text/html');

\t\tif (doc != null)
\t\t{
\t\t\tval = new XMLSerializer().serializeToString(doc.body);
\t\t\t
\t\t\t// Extracts body content from DOM
\t\t\tif (val.substring(0, 5) == '<body')
\t\t\t{
\t\t\t\tval = val.substring(val.indexOf('>', 5) + 1);
\t\t\t}
\t\t\t
\t\t\tif (val.substring(val.length - 7, val.length) == '</body>')
\t\t\t{
\t\t\t\tval = val.substring(0, val.length - 7);
\t\t\t}
\t\t}
\t}
\telse if (document.implementation != null && document.implementation.createDocument != null)
\t{
\t\tvar xd = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
\t\tvar xb = xd.createElement('body');
\t\txd.documentElement.appendChild(xb);
\t\t
\t\tvar div = document.createElement('div');
\t\tdiv.innerHTML = val;
\t\tvar child = div.firstChild;
\t\t
\t\twhile (child != null)
\t\t{
\t\t\tvar next = child.nextSibling;
\t\t\txb.appendChild(xd.adoptNode(child));
\t\t\tchild = next;
\t\t}
\t\t
\t\treturn xb.innerHTML;
\t}
\telse
\t{
\t\tvar ta = document.createElement('textarea');
\t\t
\t\t// Handles special HTML entities < and > and double escaping
\t\t// and converts unclosed br, hr and img tags to XHTML
\t\t// LATER: Convert all unclosed tags
\t\tta.innerHTML = val.replace(/&amp;/g, '&amp;amp;').
\t\t\treplace(/&#60;/g, '&amp;lt;').replace(/&#62;/g, '&amp;gt;').
\t\t\treplace(/&lt;/g, '&amp;lt;').replace(/&gt;/g, '&amp;gt;').
\t\t\treplace(/</g, '&lt;').replace(/>/g, '&gt;');
\t\tval = ta.value.replace(/&/g, '&amp;').replace(/&amp;lt;/g, '&lt;').
\t\t\treplace(/&amp;gt;/g, '&gt;').replace(/&amp;amp;/g, '&amp;').
\t\t\treplace(/<br>/g, '<br />').replace(/<hr>/g, '<hr />').
\t\t\treplace(/(<img[^>]+)>/gm, \"\$1 />\");
\t}
\t
\treturn val;
};

/**
 * Function: createDiv
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.createDiv = function(str)
{
\tvar val = str;
\t
\tif (!mxUtils.isNode(val))
\t{
\t\tval = '<div><div>' + this.convertHtml(val) + '</div></div>';
\t}

\t// IE uses this code for export as it cannot render foreignObjects
\tif (!mxClient.IS_IE && !mxClient.IS_IE11 && document.createElementNS)
\t{
\t\tvar div = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
\t\t
\t\tif (mxUtils.isNode(val))
\t\t{
\t\t\tvar div2 = document.createElement('div');
\t\t\tvar div3 = div2.cloneNode(false);
\t\t\t
\t\t\t// Creates a copy for export
\t\t\tif (this.root.ownerDocument != document)
\t\t\t{
\t\t\t\tdiv2.appendChild(val.cloneNode(true));
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdiv2.appendChild(val);
\t\t\t}
\t\t\t
\t\t\tdiv3.appendChild(div2);
\t\t\tdiv.appendChild(div3);
\t\t}
\t\telse
\t\t{
\t\t\tdiv.innerHTML = val;
\t\t}
\t\t
\t\treturn div;
\t}
\telse
\t{
\t\tif (mxUtils.isNode(val))
\t\t{
\t\t\tval = '<div><div>' + mxUtils.getXml(val) + '</div></div>';
\t\t}
\t\t
\t\tval = '<div xmlns=\"http://www.w3.org/1999/xhtml\">' + val + '</div>';

\t\t// NOTE: FF 3.6 crashes if content CSS contains \"height:100%\"
\t\treturn  mxUtils.parseXml(val).documentElement;
\t}
};

/**
 * Updates existing DOM nodes for text rendering. LATER: Merge common parts with text function below.
 */
mxSvgCanvas2D.prototype.updateText = function(x, y, w, h, align, valign, wrap, overflow, clip, rotation, node)
{
\tif (node != null && node.firstChild != null && node.firstChild.firstChild != null)
\t{
\t\tthis.updateTextNodes(x, y, w, h, align, valign, wrap, overflow, clip, rotation, node.firstChild);
\t}
};

/**
 * Function: addForeignObject
 * 
 * Creates a foreignObject for the given string and adds it to the given root.
 */
mxSvgCanvas2D.prototype.addForeignObject = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir, div, root)
{
\tvar group = this.createElement('g');
\tvar fo = this.createElement('foreignObject');
\t
\t// Workarounds for print clipping and static position in Safari
\tfo.setAttribute('style', 'overflow: visible; text-align: left;');
\tfo.setAttribute('pointer-events', 'none');
\t
\t// Import needed for older versions of IE
\tif (div.ownerDocument != document)
\t{
\t\tdiv = mxUtils.importNodeImplementation(fo.ownerDocument, div, true);
\t}

\tfo.appendChild(div);
\tgroup.appendChild(fo);

\tthis.updateTextNodes(x, y, w, h, align, valign, wrap, overflow, clip, rotation, group);
\t
\t// Alternate content if foreignObject not supported
\tif (this.root.ownerDocument != document)
\t{
\t\tvar alt = this.createAlternateContent(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation);
\t\t
\t\tif (alt != null)
\t\t{
\t\t\tfo.setAttribute('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility');
\t\t\tvar sw = this.createElement('switch');
\t\t\tsw.appendChild(fo);
\t\t\tsw.appendChild(alt);
\t\t\tgroup.appendChild(sw);
\t\t}
\t}
\t
\troot.appendChild(group);
};

/**
 * Updates existing DOM nodes for text rendering.
 */
mxSvgCanvas2D.prototype.updateTextNodes = function(x, y, w, h, align, valign, wrap, overflow, clip, rotation, g)
{
\tvar s = this.state.scale;

\tmxSvgCanvas2D.createCss(w + 2, h, align, valign, wrap, overflow, clip,
\t\t(this.state.fontBackgroundColor != null) ? this.state.fontBackgroundColor : null,
\t\t(this.state.fontBorderColor != null) ? this.state.fontBorderColor : null,
\t\t'display: flex; align-items: unsafe ' +
\t\t((valign == mxConstants.ALIGN_TOP) ? 'flex-start' :
\t\t((valign == mxConstants.ALIGN_BOTTOM) ? 'flex-end' : 'center'))  + '; ' +
\t\t'justify-content: unsafe ' + ((align == mxConstants.ALIGN_LEFT) ? 'flex-start' :
\t\t((align == mxConstants.ALIGN_RIGHT) ? 'flex-end' : 'center'))  + '; ',
\t\tthis.getTextCss(), s, mxUtils.bind(this, function(dx, dy, flex, item, block)
\t{
\t\tx += this.state.dx;
\t\ty += this.state.dy;

\t\tvar fo = g.firstChild;
\t\tvar div = fo.firstChild;
\t\tvar box = div.firstChild;
\t\tvar text = box.firstChild;
\t\tvar r = ((this.rotateHtml) ? this.state.rotation : 0) + ((rotation != null) ? rotation : 0);
\t\tvar t = ((this.foOffset != 0) ? 'translate(' + this.foOffset + ' ' + this.foOffset + ')' : '') +
\t\t\t((s != 1) ? 'scale(' + s + ')' : '');
\t\t
\t\ttext.setAttribute('style', block);
\t\tbox.setAttribute('style', item);
\t\t
\t\t// Workaround for clipping in Webkit with scrolling and zoom
\t\tfo.setAttribute('width', Math.ceil(1 / Math.min(1, s) * 100) + '%');
\t\tfo.setAttribute('height', Math.ceil(1 / Math.min(1, s) * 100) + '%');
\t\tvar yp = Math.round(y + dy);
\t\t
\t\t// Allows for negative values which are causing problems with
\t\t// transformed content where the top edge of the foreignObject
\t\t// limits the text box being moved further up in the diagram.
\t\t// KNOWN: Possible clipping problems with zoom and scrolling
\t\t// but this is normally not used with scrollbars as the
\t\t// coordinates are always positive with scrollbars.
\t\t// Margin-top is ignored in Safari and no negative values allowed
\t\t// for padding.
\t\tif (yp < 0)
\t\t{
\t\t\tfo.setAttribute('y', yp);
\t\t}
\t\telse
\t\t{
\t\t\tfo.removeAttribute('y');
\t\t\tflex += 'padding-top: ' + yp + 'px; ';
\t\t}
\t\t
\t\tdiv.setAttribute('style', flex + 'margin-left: ' + Math.round(x + dx) + 'px;');
\t\tt += ((r != 0) ? ('rotate(' + r + ' ' + x + ' ' + y + ')') : '');

\t\t// Output allows for reflow but Safari cannot use absolute position,
\t\t// transforms or opacity. https://bugs.webkit.org/show_bug.cgi?id=23113
\t\tif (t != '')
\t\t{\t
\t\t\tg.setAttribute('transform', t);
\t\t}
\t\telse
\t\t{
\t\t\tg.removeAttribute('transform');
\t\t}
\t\t
\t\tif (this.state.alpha != 1)
\t\t{
\t\t\tg.setAttribute('opacity', this.state.alpha);
\t\t}
\t\telse
\t\t{
\t\t\tg.removeAttribute('opacity');
\t\t}
\t}));
};

/**
 * Updates existing DOM nodes for text rendering.
 */
mxSvgCanvas2D.createCss = function(w, h, align, valign, wrap, overflow, clip, bg, border, flex, block, s, callback)
{
\tvar item = 'box-sizing: border-box; font-size: 0; text-align: ' + ((align == mxConstants.ALIGN_LEFT) ? 'left' :
\t\t((align == mxConstants.ALIGN_RIGHT) ? 'right' : 'center')) + '; ';
\tvar pt = mxUtils.getAlignmentAsPoint(align, valign);
\tvar ofl = 'overflow: hidden; ';
\tvar fw = 'width: 1px; ';
\tvar fh = 'height: 1px; ';
\tvar dx = pt.x * w;
\tvar dy = pt.y * h;
\t
\tif (clip)
\t{
\t\tfw = 'width: ' + Math.round(w) + 'px; ';
\t\titem += 'max-height: ' + Math.round(h) + 'px; ';
\t\tdy = 0;
\t}
\telse if (overflow == 'fill')
\t{
\t\tfw = 'width: ' + Math.round(w) + 'px; ';
\t\tfh = 'height: ' + Math.round(h) + 'px; ';
\t\tblock += 'width: 100%; height: 100%; ';
\t\titem += fw + fh;
\t}
\telse if (overflow == 'width')
\t{
\t\tfw = 'width: ' + Math.round(w) + 'px; ';
\t\tblock += 'width: 100%; ';
\t\titem += fw;
\t\tdy = 0;
\t\t
\t\tif (h > 0)
\t\t{
\t\t\titem += 'max-height: ' + Math.round(h) + 'px; ';
\t\t}
\t}
\telse
\t{
\t\tofl = '';
\t\tdy = 0;
\t}
\t
\tvar bgc = '';
\t
\tif (bg != null)
\t{
\t\tbgc += 'background-color: ' + bg + '; ';
\t}
\t
\tif (border != null)
\t{
\t\tbgc += 'border: 1px solid ' + border + '; ';
\t}
\t
\tif (ofl == '' || clip)
\t{
\t\tblock += bgc;
\t}
\telse
\t{
\t\titem += bgc;
\t}

\tif (wrap && w > 0)
\t{
\t\tblock += 'white-space: normal; word-wrap: ' + mxConstants.WORD_WRAP + '; ';
\t\tfw = 'width: ' + Math.round(w) + 'px; ';
\t\t
\t\tif (ofl != '' && overflow != 'fill')
\t\t{
\t\t\tdy = 0;
\t\t}
\t}
\telse
\t{
\t\tblock += 'white-space: nowrap; ';
\t\t
\t\tif (ofl == '')
\t\t{
\t\t\tdx = 0;
\t\t}
\t}
\t
\tcallback(dx, dy, flex + fw + fh, item + ofl, block, ofl);
};

/**
 * Function: getTextCss
 * 
 * Private helper function to create SVG elements
 */
mxSvgCanvas2D.prototype.getTextCss = function()
{
\tvar s = this.state;
\tvar lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (s.fontSize * mxConstants.LINE_HEIGHT) + 'px' :
\t\t(mxConstants.LINE_HEIGHT * this.lineHeightCorrection);
\tvar css = 'display: inline-block; font-size: ' + s.fontSize + 'px; ' +
\t\t'font-family: ' + s.fontFamily + '; color: ' + s.fontColor + '; line-height: ' + lh +
\t\t'; pointer-events: ' + ((this.pointerEvents) ? this.pointerEventsValue : 'none') + '; ';
\t
\tif ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\tcss += 'font-weight: bold; ';
\t}

\tif ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\tcss += 'font-style: italic; ';
\t}

\tvar deco = [];
\t
\tif ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\tdeco.push('underline');
\t}
\t
\tif ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t{
\t\tdeco.push('line-through');
\t}
\t
\tif (deco.length > 0)
\t{
\t\tcss += 'text-decoration: ' + deco.join(' ') + '; ';
\t}

\treturn css;
};

/**
 * Function: text
 * 
 * Paints the given text. Possible values for format are empty string for plain
 * text and html for HTML markup. Note that HTML markup is only supported if
 * foreignObject is supported and <foEnabled> is true. (This means IE9 and later
 * does currently not support HTML text as part of shapes.)
 */
mxSvgCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
{
\tif (this.textEnabled && str != null)
\t{
\t\trotation = (rotation != null) ? rotation : 0;

\t\tif (this.foEnabled && format == 'html')
\t\t{
\t\t\tvar div = this.createDiv(str);
\t\t\t
\t\t\t// Ignores invalid XHTML labels
\t\t\tif (div != null)
\t\t\t{
\t\t\t\tif (dir != null)
\t\t\t\t{
\t\t\t\t\tdiv.setAttribute('dir', dir);
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.addForeignObject(x, y, w, h, str, align, valign, wrap,
\t\t\t\t\tformat, overflow, clip, rotation, dir, div, this.root);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tthis.plainText(x + this.state.dx, y + this.state.dy, w, h, str,
\t\t\t\talign, valign, wrap, overflow, clip, rotation, dir);
\t\t}
\t}
};

/**
 * Function: createClip
 * 
 * Creates a clip for the given coordinates.
 */
mxSvgCanvas2D.prototype.createClip = function(x, y, w, h)
{
\tx = Math.round(x);
\ty = Math.round(y);
\tw = Math.round(w);
\th = Math.round(h);
\t
\tvar id = 'mx-clip-' + x + '-' + y + '-' + w + '-' + h;

\tvar counter = 0;
\tvar tmp = id + '-' + counter;
\t
\t// Resolves ID conflicts
\twhile (document.getElementById(tmp) != null)
\t{
\t\ttmp = id + '-' + (++counter);
\t}
\t
\tclip = this.createElement('clipPath');
\tclip.setAttribute('id', tmp);
\t
\tvar rect = this.createElement('rect');
\trect.setAttribute('x', x);
\trect.setAttribute('y', y);
\trect.setAttribute('width', w);
\trect.setAttribute('height', h);
\t\t
\tclip.appendChild(rect);
\t
\treturn clip;
};

/**
 * Function: plainText
 * 
 * Paints the given text. Possible values for format are empty string for
 * plain text and html for HTML markup.
 */
mxSvgCanvas2D.prototype.plainText = function(x, y, w, h, str, align, valign, wrap, overflow, clip, rotation, dir)
{
\trotation = (rotation != null) ? rotation : 0;
\tvar s = this.state;
\tvar size = s.fontSize;
\tvar node = this.createElement('g');
\tvar tr = s.transform || '';
\tthis.updateFont(node);
\t\t\t\t
\t// Ignores pointer events
\tif (!this.pointerEvents && this.originalRoot == null)
\t{
\t\tnode.setAttribute('pointer-events', 'none');
\t}
\t\t
\t// Non-rotated text
\tif (rotation != 0)
\t{
\t\ttr += 'rotate(' + rotation  + ',' + this.format(x * s.scale) + ',' + this.format(y * s.scale) + ')';
\t}
\t
\tif (dir != null)
\t{
\t\tnode.setAttribute('direction', dir);
\t}

\tif (clip && w > 0 && h > 0)
\t{
\t\tvar cx = x;
\t\tvar cy = y;
\t\t
\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t{
\t\t\tcx -= w / 2;
\t\t}
\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t{
\t\t\tcx -= w;
\t\t}
\t\t
\t\tif (overflow != 'fill')
\t\t{
\t\t\tif (valign == mxConstants.ALIGN_MIDDLE)
\t\t\t{
\t\t\t\tcy -= h / 2;
\t\t\t}
\t\t\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t\t\t{
\t\t\t\tcy -= h;
\t\t\t}
\t\t}
\t\t
\t\t// LATER: Remove spacing from clip rectangle
\t\tvar c = this.createClip(cx * s.scale - 2, cy * s.scale - 2, w * s.scale + 4, h * s.scale + 4);
\t\t
\t\tif (this.defs != null)
\t\t{
\t\t\tthis.defs.appendChild(c);
\t\t}
\t\telse
\t\t{
\t\t\t// Makes sure clip is removed with referencing node
\t\t\tthis.root.appendChild(c);
\t\t}
\t\t
\t\tif (!mxClient.IS_CHROMEAPP && !mxClient.IS_IE && !mxClient.IS_IE11 &&
\t\t\t!mxClient.IS_EDGE && this.root.ownerDocument == document)
\t\t{
\t\t\t// Workaround for potential base tag
\t\t\tvar base = this.getBaseUrl().replace(/([\\(\\)])/g, '\\\\\$1');
\t\t\tnode.setAttribute('clip-path', 'url(' + base + '#' + c.getAttribute('id') + ')');
\t\t}
\t\telse
\t\t{
\t\t\tnode.setAttribute('clip-path', 'url(#' + c.getAttribute('id') + ')');
\t\t}
\t}

\t// Default is left
\tvar anchor = (align == mxConstants.ALIGN_RIGHT) ? 'end' :
\t\t\t\t\t(align == mxConstants.ALIGN_CENTER) ? 'middle' :
\t\t\t\t\t'start';

\t// Text-anchor start is default in SVG
\tif (anchor != 'start')
\t{
\t\tnode.setAttribute('text-anchor', anchor);
\t}
\t
\tif (!this.styleEnabled || size != mxConstants.DEFAULT_FONTSIZE)
\t{
\t\tnode.setAttribute('font-size', (size * s.scale) + 'px');
\t}
\t
\tif (tr.length > 0)
\t{
\t\tnode.setAttribute('transform', tr);
\t}
\t
\tif (s.alpha < 1)
\t{
\t\tnode.setAttribute('opacity', s.alpha);
\t}
\t
\tvar lines = str.split('\\n');
\tvar lh = Math.round(size * mxConstants.LINE_HEIGHT);
\tvar textHeight = size + (lines.length - 1) * lh;

\tvar cy = y + size - 1;

\tif (valign == mxConstants.ALIGN_MIDDLE)
\t{
\t\tif (overflow == 'fill')
\t\t{
\t\t\tcy -= h / 2;
\t\t}
\t\telse
\t\t{
\t\t\tvar dy = ((this.matchHtmlAlignment && clip && h > 0) ? Math.min(textHeight, h) : textHeight) / 2;
\t\t\tcy -= dy;
\t\t}
\t}
\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t{
\t\tif (overflow == 'fill')
\t\t{
\t\t\tcy -= h;
\t\t}
\t\telse
\t\t{
\t\t\tvar dy = (this.matchHtmlAlignment && clip && h > 0) ? Math.min(textHeight, h) : textHeight;
\t\t\tcy -= dy + 1;
\t\t}
\t}

\tfor (var i = 0; i < lines.length; i++)
\t{
\t\t// Workaround for bounding box of empty lines and spaces
\t\tif (lines[i].length > 0 && mxUtils.trim(lines[i]).length > 0)
\t\t{
\t\t\tvar text = this.createElement('text');
\t\t\t// LATER: Match horizontal HTML alignment
\t\t\ttext.setAttribute('x', this.format(x * s.scale) + this.textOffset);
\t\t\ttext.setAttribute('y', this.format(cy * s.scale) + this.textOffset);
\t
\t\t\tmxUtils.write(text, lines[i]);
\t\t\tnode.appendChild(text);
\t\t}

\t\tcy += lh;
\t}

\tthis.root.appendChild(node);
\tthis.addTextBackground(node, str, x, y, w, (overflow == 'fill') ? h : textHeight, align, valign, overflow);
};

/**
 * Function: updateFont
 * 
 * Updates the text properties for the given node. (NOTE: For this to work in
 * IE, the given node must be a text or tspan element.)
 */
mxSvgCanvas2D.prototype.updateFont = function(node)
{
\tvar s = this.state;

\tnode.setAttribute('fill', s.fontColor);
\t
\tif (!this.styleEnabled || s.fontFamily != mxConstants.DEFAULT_FONTFAMILY)
\t{
\t\tnode.setAttribute('font-family', s.fontFamily);
\t}

\tif ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\tnode.setAttribute('font-weight', 'bold');
\t}

\tif ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\tnode.setAttribute('font-style', 'italic');
\t}
\t
\tvar txtDecor = [];
\t
\tif ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\ttxtDecor.push('underline');
\t}
\t
\tif ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t{
\t\ttxtDecor.push('line-through');
\t}
\t
\tif (txtDecor.length > 0)
\t{
\t\tnode.setAttribute('text-decoration', txtDecor.join(' '));
\t}
};

/**
 * Function: addTextBackground
 * 
 * Background color and border
 */
mxSvgCanvas2D.prototype.addTextBackground = function(node, str, x, y, w, h, align, valign, overflow)
{
\tvar s = this.state;

\tif (s.fontBackgroundColor != null || s.fontBorderColor != null)
\t{
\t\tvar bbox = null;
\t\t
\t\tif (overflow == 'fill' || overflow == 'width')
\t\t{
\t\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t\t{
\t\t\t\tx -= w / 2;
\t\t\t}
\t\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t\t{
\t\t\t\tx -= w;
\t\t\t}
\t\t\t
\t\t\tif (valign == mxConstants.ALIGN_MIDDLE)
\t\t\t{
\t\t\t\ty -= h / 2;
\t\t\t}
\t\t\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t\t\t{
\t\t\t\ty -= h;
\t\t\t}
\t\t\t
\t\t\tbbox = new mxRectangle((x + 1) * s.scale, y * s.scale, (w - 2) * s.scale, (h + 2) * s.scale);
\t\t}
\t\telse if (node.getBBox != null && this.root.ownerDocument == document)
\t\t{
\t\t\t// Uses getBBox only if inside document for correct size
\t\t\ttry
\t\t\t{
\t\t\t\tbbox = node.getBBox();
\t\t\t\tvar ie = mxClient.IS_IE && mxClient.IS_SVG;
\t\t\t\tbbox = new mxRectangle(bbox.x, bbox.y + ((ie) ? 0 : 1), bbox.width, bbox.height + ((ie) ? 1 : 0));
\t\t\t}
\t\t\tcatch (e)
\t\t\t{
\t\t\t\t// Ignores NS_ERROR_FAILURE in FF if container display is none.
\t\t\t}
\t\t}
\t\t
\t\tif (bbox == null || bbox.width == 0 || bbox.height == 0)
\t\t{
\t\t\t// Computes size if not in document or no getBBox available
\t\t\tvar div = document.createElement('div');

\t\t\t// Wrapping and clipping can be ignored here
\t\t\tdiv.style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (s.fontSize * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
\t\t\tdiv.style.fontSize = s.fontSize + 'px';
\t\t\tdiv.style.fontFamily = s.fontFamily;
\t\t\tdiv.style.whiteSpace = 'nowrap';
\t\t\tdiv.style.position = 'absolute';
\t\t\tdiv.style.visibility = 'hidden';
\t\t\tdiv.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
\t\t\tdiv.style.zoom = '1';
\t\t\t
\t\t\tif ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t\t\t{
\t\t\t\tdiv.style.fontWeight = 'bold';
\t\t\t}

\t\t\tif ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t\t\t{
\t\t\t\tdiv.style.fontStyle = 'italic';
\t\t\t}
\t\t\t
\t\t\tstr = mxUtils.htmlEntities(str, false);
\t\t\tdiv.innerHTML = str.replace(/\\n/g, '<br/>');
\t\t\t
\t\t\tdocument.body.appendChild(div);
\t\t\tvar w = div.offsetWidth;
\t\t\tvar h = div.offsetHeight;
\t\t\tdiv.parentNode.removeChild(div);
\t\t\t
\t\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t\t{
\t\t\t\tx -= w / 2;
\t\t\t}
\t\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t\t{
\t\t\t\tx -= w;
\t\t\t}
\t\t\t
\t\t\tif (valign == mxConstants.ALIGN_MIDDLE)
\t\t\t{
\t\t\t\ty -= h / 2;
\t\t\t}
\t\t\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t\t\t{
\t\t\t\ty -= h;
\t\t\t}
\t\t\t
\t\t\tbbox = new mxRectangle((x + 1) * s.scale, (y + 2) * s.scale, w * s.scale, (h + 1) * s.scale);
\t\t}
\t\t
\t\tif (bbox != null)
\t\t{
\t\t\tvar n = this.createElement('rect');
\t\t\tn.setAttribute('fill', s.fontBackgroundColor || 'none');
\t\t\tn.setAttribute('stroke', s.fontBorderColor || 'none');
\t\t\tn.setAttribute('x', Math.floor(bbox.x - 1));
\t\t\tn.setAttribute('y', Math.floor(bbox.y - 1));
\t\t\tn.setAttribute('width', Math.ceil(bbox.width + 2));
\t\t\tn.setAttribute('height', Math.ceil(bbox.height));

\t\t\tvar sw = (s.fontBorderColor != null) ? Math.max(1, this.format(s.scale)) : 0;
\t\t\tn.setAttribute('stroke-width', sw);
\t\t\t
\t\t\t// Workaround for crisp rendering - only required if not exporting
\t\t\tif (this.root.ownerDocument == document && mxUtils.mod(sw, 2) == 1)
\t\t\t{
\t\t\t\tn.setAttribute('transform', 'translate(0.5, 0.5)');
\t\t\t}
\t\t\t
\t\t\tnode.insertBefore(n, node.firstChild);
\t\t}
\t}
};

/**
 * Function: stroke
 * 
 * Paints the outline of the current path.
 */
mxSvgCanvas2D.prototype.stroke = function()
{
\tthis.addNode(false, true);
};

/**
 * Function: fill
 * 
 * Fills the current path.
 */
mxSvgCanvas2D.prototype.fill = function()
{
\tthis.addNode(true, false);
};

/**
 * Function: fillAndStroke
 * 
 * Fills and paints the outline of the current path.
 */
mxSvgCanvas2D.prototype.fillAndStroke = function()
{
\tthis.addNode(true, true);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 *
 * Class: mxVmlCanvas2D
 * 
 * Implements a canvas to be used for rendering VML. Here is an example of implementing a
 * fallback for SVG images which are not supported in VML-based browsers.
 * 
 * (code)
 * var mxVmlCanvas2DImage = mxVmlCanvas2D.prototype.image;
 * mxVmlCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
 * {
 *   if (src.substring(src.length - 4, src.length) == '.svg')
 *   {
 *     src = 'http://www.jgraph.com/images/mxgraph.gif';
 *   }
 *   
 *   mxVmlCanvas2DImage.apply(this, arguments);
 * };
 * (end)
 * 
 * To disable anti-aliasing in the output, use the following code.
 * 
 * (code)
 * document.createStyleSheet().cssText = mxClient.VML_PREFIX + '\\\\:*{antialias:false;)}';
 * (end)
 * 
 * A description of the public API is available in <mxXmlCanvas2D>. Note that
 * there is a known issue in VML where gradients are painted using the outer
 * bounding box of rotated shapes, not the actual bounds of the shape. See
 * also <text> for plain text label restrictions in shapes for VML.
 */
var mxVmlCanvas2D = function(root)
{
\tmxAbstractCanvas2D.call(this);

\t/**
\t * Variable: root
\t * 
\t * Reference to the container for the SVG content.
\t */
\tthis.root = root;
};

/**
 * Extends mxAbstractCanvas2D
 */
mxUtils.extend(mxVmlCanvas2D, mxAbstractCanvas2D);

/**
 * Variable: path
 * 
 * Holds the current DOM node.
 */
mxVmlCanvas2D.prototype.node = null;

/**
 * Variable: textEnabled
 * 
 * Specifies if text output should be enabledetB. Default is true.
 */
mxVmlCanvas2D.prototype.textEnabled = true;

/**
 * Variable: moveOp
 * 
 * Contains the string used for moving in paths. Default is 'm'.
 */
mxVmlCanvas2D.prototype.moveOp = 'm';

/**
 * Variable: lineOp
 * 
 * Contains the string used for moving in paths. Default is 'l'.
 */
mxVmlCanvas2D.prototype.lineOp = 'l';

/**
 * Variable: curveOp
 * 
 * Contains the string used for bezier curves. Default is 'c'.
 */
mxVmlCanvas2D.prototype.curveOp = 'c';

/**
 * Variable: closeOp
 * 
 * Holds the operator for closing curves. Default is 'x e'.
 */
mxVmlCanvas2D.prototype.closeOp = 'x';

/**
 * Variable: rotatedHtmlBackground
 * 
 * Background color for rotated HTML. Default is ''. This can be set to eg.
 * white to improve rendering of rotated text in VML for IE9.
 */
mxVmlCanvas2D.prototype.rotatedHtmlBackground = '';

/**
 * Variable: vmlScale
 * 
 * Specifies the scale used to draw VML shapes.
 */
mxVmlCanvas2D.prototype.vmlScale = 1;

/**
 * Function: createElement
 * 
 * Creates the given element using the document.
 */
mxVmlCanvas2D.prototype.createElement = function(name)
{
\treturn document.createElement(name);
};

/**
 * Function: createVmlElement
 * 
 * Creates a new element using <createElement> and prefixes the given name with
 * <mxClient.VML_PREFIX>.
 */
mxVmlCanvas2D.prototype.createVmlElement = function(name)
{
\treturn this.createElement(mxClient.VML_PREFIX + ':' + name);
};

/**
 * Function: addNode
 * 
 * Adds the current node to the <root>.
 */
mxVmlCanvas2D.prototype.addNode = function(filled, stroked)
{
\tvar node = this.node;
\tvar s = this.state;
\t
\tif (node != null)
\t{
\t\tif (node.nodeName == 'shape')
\t\t{
\t\t\t// Checks if the path is not empty
\t\t\tif (this.path != null && this.path.length > 0)
\t\t\t{
\t\t\t\tnode.path = this.path.join(' ') + ' e';
\t\t\t\tnode.style.width = this.root.style.width;
\t\t\t\tnode.style.height = this.root.style.height;
\t\t\t\tnode.coordsize = parseInt(node.style.width) + ' ' + parseInt(node.style.height);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t}

\t\tnode.strokeweight = this.format(Math.max(1, s.strokeWidth * s.scale / this.vmlScale)) + 'px';
\t\t
\t\tif (s.shadow)
\t\t{
\t\t\tthis.root.appendChild(this.createShadow(node,
\t\t\t\tfilled && s.fillColor != null,
\t\t\t\tstroked && s.strokeColor != null));
\t\t}
\t\t
\t\tif (stroked && s.strokeColor != null)
\t\t{
\t\t\tnode.stroked = 'true';
\t\t\tnode.strokecolor = s.strokeColor;
\t\t}
\t\telse
\t\t{
\t\t\tnode.stroked = 'false';
\t\t}

\t\tnode.appendChild(this.createStroke());

\t\tif (filled && s.fillColor != null)
\t\t{
\t\t\tnode.appendChild(this.createFill());
\t\t}
\t\telse if (this.pointerEvents && (node.nodeName != 'shape' ||
\t\t\tthis.path[this.path.length - 1] == this.closeOp))
\t\t{
\t\t\tnode.appendChild(this.createTransparentFill());
\t\t}
\t\telse
\t\t{
\t\t\tnode.filled = 'false';
\t\t}

\t\t// LATER: Update existing DOM for performance
\t\tthis.root.appendChild(node);
\t}
};

/**
 * Function: createTransparentFill
 * 
 * Creates a transparent fill.
 */
mxVmlCanvas2D.prototype.createTransparentFill = function()
{
\tvar fill = this.createVmlElement('fill');
\tfill.src = mxClient.imageBasePath + '/transparent.gif';
\tfill.type = 'tile';
\t
\treturn fill;
};

/**
 * Function: createFill
 * 
 * Creates a fill for the current state.
 */
mxVmlCanvas2D.prototype.createFill = function()
{
\tvar s = this.state;
\t
\t// Gradients in foregrounds not supported because special gradients
\t// with bounds must be created for each element in graphics-canvases
\tvar fill = this.createVmlElement('fill');
\tfill.color = s.fillColor;

\tif (s.gradientColor != null)
\t{
\t\tfill.type = 'gradient';
\t\tfill.method = 'none';
\t\tfill.color2 = s.gradientColor;
\t\tvar angle = 180 - s.rotation;
\t\t
\t\tif (s.gradientDirection == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tangle -= 90 + ((this.root.style.flip == 'x') ? 180 : 0);
\t\t}
\t\telse if (s.gradientDirection == mxConstants.DIRECTION_EAST)
\t\t{
\t\t\tangle += 90 + ((this.root.style.flip == 'x') ? 180 : 0);
\t\t}
\t\telse if (s.gradientDirection == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\tangle -= 180 + ((this.root.style.flip == 'y') ? -180 : 0);
\t\t}
\t\telse
\t\t{
\t\t\t angle += ((this.root.style.flip == 'y') ? -180 : 0);
\t\t}
\t\t
\t\tif (this.root.style.flip == 'x' || this.root.style.flip == 'y')
\t\t{
\t\t\tangle *= -1;
\t\t}

\t\t// LATER: Fix outer bounding box for rotated shapes used in VML.
\t\tfill.angle = mxUtils.mod(angle, 360);
\t\tfill.opacity = (s.alpha * s.gradientFillAlpha * 100) + '%';
\t\tfill.setAttribute(mxClient.OFFICE_PREFIX + ':opacity2', (s.alpha * s.gradientAlpha * 100) + '%');
\t}
\telse if (s.alpha < 1 || s.fillAlpha < 1)
\t{
\t\tfill.opacity = (s.alpha * s.fillAlpha * 100) + '%';\t\t\t
\t}
\t
\treturn fill;
};
/**
 * Function: createStroke
 * 
 * Creates a fill for the current state.
 */
mxVmlCanvas2D.prototype.createStroke = function()
{
\tvar s = this.state;
\tvar stroke = this.createVmlElement('stroke');
\tstroke.endcap = s.lineCap || 'flat';
\tstroke.joinstyle = s.lineJoin || 'miter';
\tstroke.miterlimit = s.miterLimit || '10';
\t
\tif (s.alpha < 1 || s.strokeAlpha < 1)
\t{
\t\tstroke.opacity = (s.alpha * s.strokeAlpha * 100) + '%';
\t}
\t
\tif (s.dashed)
\t{
\t\tstroke.dashstyle = this.getVmlDashStyle();
\t}
\t
\treturn stroke;
};

/**
 * Function: getVmlDashPattern
 * 
 * Returns a VML dash pattern for the current dashPattern.
 * See http://msdn.microsoft.com/en-us/library/bb264085(v=vs.85).aspx
 */
mxVmlCanvas2D.prototype.getVmlDashStyle = function()
{
\tvar result = 'dash';
\t
\tif (typeof(this.state.dashPattern) === 'string')
\t{
\t\tvar tok = this.state.dashPattern.split(' ');
\t\t
\t\tif (tok.length > 0 && tok[0] == 1)
\t\t{
\t\t\tresult = '0 2';
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: createShadow
 * 
 * Creates a shadow for the given node.
 */
mxVmlCanvas2D.prototype.createShadow = function(node, filled, stroked)
{
\tvar s = this.state;
\tvar rad = -s.rotation * (Math.PI / 180);
\tvar cos = Math.cos(rad);
\tvar sin = Math.sin(rad);

\tvar dx = s.shadowDx * s.scale;
\tvar dy = s.shadowDy * s.scale;

\tif (this.root.style.flip == 'x')
\t{
\t\tdx *= -1;
\t}
\telse if (this.root.style.flip == 'y')
\t{
\t\tdy *= -1;
\t}
\t
\tvar shadow = node.cloneNode(true);
\tshadow.style.marginLeft = Math.round(dx * cos - dy * sin) + 'px';
\tshadow.style.marginTop = Math.round(dx * sin + dy * cos) + 'px';

\t// Workaround for wrong cloning in IE8 standards mode
\tif (document.documentMode == 8)
\t{
\t\tshadow.strokeweight = node.strokeweight;
\t\t
\t\tif (node.nodeName == 'shape')
\t\t{
\t\t\tshadow.path = this.path.join(' ') + ' e';
\t\t\tshadow.style.width = this.root.style.width;
\t\t\tshadow.style.height = this.root.style.height;
\t\t\tshadow.coordsize = parseInt(node.style.width) + ' ' + parseInt(node.style.height);
\t\t}
\t}
\t
\tif (stroked)
\t{
\t\tshadow.strokecolor = s.shadowColor;
\t\tshadow.appendChild(this.createShadowStroke());
\t}
\telse
\t{
\t\tshadow.stroked = 'false';
\t}
\t
\tif (filled)
\t{
\t\tshadow.appendChild(this.createShadowFill());
\t}
\telse
\t{
\t\tshadow.filled = 'false';
\t}
\t
\treturn shadow;
};

/**
 * Function: createShadowFill
 * 
 * Creates the fill for the shadow.
 */
mxVmlCanvas2D.prototype.createShadowFill = function()
{
\tvar fill = this.createVmlElement('fill');
\tfill.color = this.state.shadowColor;
\tfill.opacity = (this.state.alpha * this.state.shadowAlpha * 100) + '%';
\t
\treturn fill;
};

/**
 * Function: createShadowStroke
 * 
 * Creates the stroke for the shadow.
 */
mxVmlCanvas2D.prototype.createShadowStroke = function()
{
\tvar stroke = this.createStroke();
\tstroke.opacity = (this.state.alpha * this.state.shadowAlpha * 100) + '%';
\t
\treturn stroke;
};

/**
 * Function: rotate
 * 
 * Sets the rotation of the canvas. Note that rotation cannot be concatenated.
 */
mxVmlCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
{
\tif (flipH && flipV)
\t{
\t\ttheta += 180;
\t}
\telse if (flipH)
\t{
\t\tthis.root.style.flip = 'x';
\t}
\telse if (flipV)
\t{
\t\tthis.root.style.flip = 'y';
\t}

\tif (flipH ? !flipV : flipV)
\t{
\t\ttheta *= -1;
\t}

\tthis.root.style.rotation = theta;
\tthis.state.rotation = this.state.rotation + theta;
\tthis.state.rotationCx = cx;
\tthis.state.rotationCy = cy;
};

/**
 * Function: begin
 * 
 * Extends superclass to create path.
 */
mxVmlCanvas2D.prototype.begin = function()
{
\tmxAbstractCanvas2D.prototype.begin.apply(this, arguments);
\tthis.node = this.createVmlElement('shape');
\tthis.node.style.position = 'absolute';
};

/**
 * Function: quadTo
 * 
 * Replaces quadratic curve with bezier curve in VML.
 */
mxVmlCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
{
\tvar s = this.state;

\tvar cpx0 = (this.lastX + s.dx) * s.scale;
\tvar cpy0 = (this.lastY + s.dy) * s.scale;
\tvar qpx1 = (x1 + s.dx) * s.scale;
\tvar qpy1 = (y1 + s.dy) * s.scale;
\tvar cpx3 = (x2 + s.dx) * s.scale;
\tvar cpy3 = (y2 + s.dy) * s.scale;
\t
\tvar cpx1 = cpx0 + 2/3 * (qpx1 - cpx0);
\tvar cpy1 = cpy0 + 2/3 * (qpy1 - cpy0);
\t
\tvar cpx2 = cpx3 + 2/3 * (qpx1 - cpx3);
\tvar cpy2 = cpy3 + 2/3 * (qpy1 - cpy3);
\t
\tthis.path.push('c ' + this.format(cpx1) + ' ' + this.format(cpy1) +
\t\t\t' ' + this.format(cpx2) + ' ' + this.format(cpy2) +
\t\t\t' ' + this.format(cpx3) + ' ' + this.format(cpy3));
\tthis.lastX = (cpx3 / s.scale) - s.dx;
\tthis.lastY = (cpy3 / s.scale) - s.dy;
\t
};

/**
 * Function: createRect
 * 
 * Sets the glass gradient.
 */
mxVmlCanvas2D.prototype.createRect = function(nodeName, x, y, w, h)
{
\tvar s = this.state;
\tvar n = this.createVmlElement(nodeName);
\tn.style.position = 'absolute';
\tn.style.left = this.format((x + s.dx) * s.scale) + 'px';
\tn.style.top = this.format((y + s.dy) * s.scale) + 'px';
\tn.style.width = this.format(w * s.scale) + 'px';
\tn.style.height = this.format(h * s.scale) + 'px';
\t
\treturn n;
};

/**
 * Function: rect
 * 
 * Sets the current path to a rectangle.
 */
mxVmlCanvas2D.prototype.rect = function(x, y, w, h)
{
\tthis.node = this.createRect('rect', x, y, w, h);
};

/**
 * Function: roundrect
 * 
 * Sets the current path to a rounded rectangle.
 */
mxVmlCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
{
\tthis.node = this.createRect('roundrect', x, y, w, h);
\t// SetAttribute needed here for IE8
\tthis.node.setAttribute('arcsize', Math.max(dx * 100 / w, dy * 100 / h) + '%');
};

/**
 * Function: ellipse
 * 
 * Sets the current path to an ellipse.
 */
mxVmlCanvas2D.prototype.ellipse = function(x, y, w, h)
{
\tthis.node = this.createRect('oval', x, y, w, h);
};

/**
 * Function: image
 * 
 * Paints an image.
 */
mxVmlCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
{
\tvar node = null;
\t
\tif (!aspect)
\t{
\t\tnode = this.createRect('image', x, y, w, h);
\t\tnode.src = src;
\t}
\telse
\t{
\t\t// Uses fill with aspect to avoid asynchronous update of size
\t\tnode = this.createRect('rect', x, y, w, h);
\t\tnode.stroked = 'false';
\t\t
\t\t// Handles image aspect via fill
\t\tvar fill = this.createVmlElement('fill');
\t\tfill.aspect = (aspect) ? 'atmost' : 'ignore';
\t\tfill.rotate = 'true';
\t\tfill.type = 'frame';
\t\tfill.src = src;

\t\tnode.appendChild(fill);
\t}
\t
\tif (flipH && flipV)
\t{
\t\tnode.style.rotation = '180';
\t}
\telse if (flipH)
\t{
\t\tnode.style.flip = 'x';
\t}
\telse if (flipV)
\t{
\t\tnode.style.flip = 'y';
\t}
\t
\tif (this.state.alpha < 1 || this.state.fillAlpha < 1)
\t{
\t\t// KNOWN: Borders around transparent images in IE<9. Using fill.opacity
\t\t// fixes this problem by adding a white background in all IE versions.
\t\tnode.style.filter += 'alpha(opacity=' + (this.state.alpha * this.state.fillAlpha * 100) + ')';
\t}

\tthis.root.appendChild(node);
};

/**
 * Function: createText
 * 
 * Creates the innermost element that contains the HTML text.
 */
mxVmlCanvas2D.prototype.createDiv = function(str, align, valign, overflow)
{
\tvar div = this.createElement('div');
\tvar state = this.state;

\tvar css = '';
\t
\tif (state.fontBackgroundColor != null)
\t{
\t\tcss += 'background-color:' + mxUtils.htmlEntities(state.fontBackgroundColor) + ';';
\t}
\t
\tif (state.fontBorderColor != null)
\t{
\t\tcss += 'border:1px solid ' + mxUtils.htmlEntities(state.fontBorderColor) + ';';
\t}
\t
\tif (mxUtils.isNode(str))
\t{
\t\tdiv.appendChild(str);
\t}
\telse
\t{
\t\tif (overflow != 'fill' && overflow != 'width')
\t\t{
\t\t\tvar div2 = this.createElement('div');
\t\t\tdiv2.style.cssText = css;
\t\t\tdiv2.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
\t\t\tdiv2.style.zoom = '1';
\t\t\tdiv2.style.textDecoration = 'inherit';
\t\t\tdiv2.innerHTML = str;
\t\t\tdiv.appendChild(div2);
\t\t}
\t\telse
\t\t{
\t\t\tdiv.style.cssText = css;
\t\t\tdiv.innerHTML = str;
\t\t}
\t}
\t
\tvar style = div.style;

\tstyle.fontSize = (state.fontSize / this.vmlScale) + 'px';
\tstyle.fontFamily = state.fontFamily;
\tstyle.color = state.fontColor;
\tstyle.verticalAlign = 'top';
\tstyle.textAlign = align || 'left';
\tstyle.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (state.fontSize * mxConstants.LINE_HEIGHT / this.vmlScale) + 'px' : mxConstants.LINE_HEIGHT;

\tif ((state.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\tstyle.fontWeight = 'bold';
\t}

\tif ((state.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\tstyle.fontStyle = 'italic';
\t}
\t
\tif ((state.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\tstyle.textDecoration = 'underline';
\t}
\t
\treturn div;
};

/**
 * Function: text
 * 
 * Paints the given text. Possible values for format are empty string for plain
 * text and html for HTML markup. Clipping, text background and border are not
 * supported for plain text in VML.
 */
mxVmlCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
{
\tif (this.textEnabled && str != null)
\t{
\t\tvar s = this.state;
\t\t
\t\tif (format == 'html')
\t\t{
\t\t\tif (s.rotation != null)
\t\t\t{
\t\t\t\tvar pt = this.rotatePoint(x, y, s.rotation, s.rotationCx, s.rotationCy);
\t\t\t\t
\t\t\t\tx = pt.x;
\t\t\t\ty = pt.y;
\t\t\t}

\t\t\tif (document.documentMode == 8 && !mxClient.IS_EM)
\t\t\t{
\t\t\t\tx += s.dx;
\t\t\t\ty += s.dy;
\t\t\t\t
\t\t\t\t// Workaround for rendering offsets
\t\t\t\tif (overflow != 'fill' && valign == mxConstants.ALIGN_TOP)
\t\t\t\t{
\t\t\t\t\ty -= 1;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tx *= s.scale;
\t\t\t\ty *= s.scale;
\t\t\t}

\t\t\t// Adds event transparency in IE8 standards without the transparent background
\t\t\t// filter which cannot be used due to bugs in the zoomed bounding box (too slow)
\t\t\t// FIXME: No event transparency if inside v:rect (ie part of shape)
\t\t\t// KNOWN: Offset wrong for rotated text with word that are longer than the wrapping
\t\t\t// width in IE8 because real width of text cannot be determined here.
\t\t\t// This should be fixed in mxText.updateBoundingBox by calling before this and
\t\t\t// passing the real width to this method if not clipped and wrapped.
\t\t\tvar abs = (document.documentMode == 8 && !mxClient.IS_EM) ? this.createVmlElement('group') : this.createElement('div');
\t\t\tabs.style.position = 'absolute';
\t\t\tabs.style.display = 'inline';
\t\t\tabs.style.left = this.format(x) + 'px';
\t\t\tabs.style.top = this.format(y) + 'px';
\t\t\tabs.style.zoom = s.scale;

\t\t\tvar box = this.createElement('div');
\t\t\tbox.style.position = 'relative';
\t\t\tbox.style.display = 'inline';
\t\t\t
\t\t\tvar margin = mxUtils.getAlignmentAsPoint(align, valign);
\t\t\tvar dx = margin.x;
\t\t\tvar dy = margin.y;

\t\t\tvar div = this.createDiv(str, align, valign, overflow);
\t\t\tvar inner = this.createElement('div');
\t\t\t
\t\t\tif (dir != null)
\t\t\t{
\t\t\t\tdiv.setAttribute('dir', dir);
\t\t\t}

\t\t\tif (wrap && w > 0)
\t\t\t{
\t\t\t\tif (!clip)
\t\t\t\t{
\t\t\t\t\tdiv.style.width = Math.round(w) + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\tdiv.style.wordWrap = mxConstants.WORD_WRAP;
\t\t\t\tdiv.style.whiteSpace = 'normal';
\t\t\t\t
\t\t\t\t// LATER: Check if other cases need to be handled
\t\t\t\tif (div.style.wordWrap == 'break-word')
\t\t\t\t{
\t\t\t\t\tvar tmp = div;
\t\t\t\t\t
\t\t\t\t\tif (tmp.firstChild != null && tmp.firstChild.nodeName == 'DIV')
\t\t\t\t\t{
\t\t\t\t\t\ttmp.firstChild.style.width = '100%';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdiv.style.whiteSpace = 'nowrap';
\t\t\t}
\t\t\t
\t\t\tvar rot = s.rotation + (rotation || 0);
\t\t\t
\t\t\tif (this.rotateHtml && rot != 0)
\t\t\t{
\t\t\t\tinner.style.display = 'inline';
\t\t\t\tinner.style.zoom = '1';
\t\t\t\tinner.appendChild(div);

\t\t\t\t// Box not needed for rendering in IE8 standards
\t\t\t\tif (document.documentMode == 8 && !mxClient.IS_EM && this.root.nodeName != 'DIV')
\t\t\t\t{
\t\t\t\t\tbox.appendChild(inner);
\t\t\t\t\tabs.appendChild(box);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tabs.appendChild(inner);
\t\t\t\t}
\t\t\t}
\t\t\telse if (document.documentMode == 8 && !mxClient.IS_EM)
\t\t\t{
\t\t\t\tbox.appendChild(div);
\t\t\t\tabs.appendChild(box);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdiv.style.display = 'inline';
\t\t\t\tabs.appendChild(div);
\t\t\t}
\t\t\t
\t\t\t// Inserts the node into the DOM
\t\t\tif (this.root.nodeName != 'DIV')
\t\t\t{
\t\t\t\t// Rectangle to fix position in group
\t\t\t\tvar rect = this.createVmlElement('rect');
\t\t\t\trect.stroked = 'false';
\t\t\t\trect.filled = 'false';

\t\t\t\trect.appendChild(abs);
\t\t\t\tthis.root.appendChild(rect);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.root.appendChild(abs);
\t\t\t}
\t\t\t
\t\t\tif (clip)
\t\t\t{
\t\t\t\tdiv.style.overflow = 'hidden';
\t\t\t\tdiv.style.width = Math.round(w) + 'px';
\t\t\t\t
\t\t\t\tif (!mxClient.IS_QUIRKS)
\t\t\t\t{
\t\t\t\t\tdiv.style.maxHeight = Math.round(h) + 'px';
\t\t\t\t}
\t\t\t}
\t\t\telse if (overflow == 'fill')
\t\t\t{
\t\t\t\t// KNOWN: Affects horizontal alignment in quirks
\t\t\t\t// but fill should only be used with align=left
\t\t\t\tdiv.style.overflow = 'hidden';
\t\t\t\tdiv.style.width = (Math.max(0, w) + 1) + 'px';
\t\t\t\tdiv.style.height = (Math.max(0, h) + 1) + 'px';
\t\t\t}
\t\t\telse if (overflow == 'width')
\t\t\t{
\t\t\t\t// KNOWN: Affects horizontal alignment in quirks
\t\t\t\t// but fill should only be used with align=left
\t\t\t\tdiv.style.overflow = 'hidden';
\t\t\t\tdiv.style.width = (Math.max(0, w) + 1) + 'px';
\t\t\t\tdiv.style.maxHeight = (Math.max(0, h) + 1) + 'px';
\t\t\t}
\t\t\t
\t\t\tif (this.rotateHtml && rot != 0)
\t\t\t{
\t\t\t\tvar rad = rot * (Math.PI / 180);
\t\t\t\t
\t\t\t\t// Precalculate cos and sin for the rotation
\t\t\t\tvar real_cos = parseFloat(parseFloat(Math.cos(rad)).toFixed(8));
\t\t\t\tvar real_sin = parseFloat(parseFloat(Math.sin(-rad)).toFixed(8));

\t\t\t\trad %= 2 * Math.PI;
\t\t\t\tif (rad < 0) rad += 2 * Math.PI;
\t\t\t\trad %= Math.PI;
\t\t\t\tif (rad > Math.PI / 2) rad = Math.PI - rad;
\t\t\t\t
\t\t\t\tvar cos = Math.cos(rad);
\t\t\t\tvar sin = Math.sin(rad);

\t\t\t\t// Adds div to document to measure size
\t\t\t\tif (document.documentMode == 8 && !mxClient.IS_EM)
\t\t\t\t{
\t\t\t\t\tdiv.style.display = 'inline-block';
\t\t\t\t\tinner.style.display = 'inline-block';
\t\t\t\t\tbox.style.display = 'inline-block';
\t\t\t\t}
\t\t\t\t
\t\t\t\tdiv.style.visibility = 'hidden';
\t\t\t\tdiv.style.position = 'absolute';
\t\t\t\tdocument.body.appendChild(div);
\t\t\t\t
\t\t\t\tvar sizeDiv = div;
\t\t\t\t
\t\t\t\tif (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
\t\t\t\t{
\t\t\t\t\tsizeDiv = sizeDiv.firstChild;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar tmp = sizeDiv.offsetWidth + 3;
\t\t\t\tvar oh = sizeDiv.offsetHeight;
\t\t\t\t
\t\t\t\tif (clip)
\t\t\t\t{
\t\t\t\t\tw = Math.min(w, tmp);
\t\t\t\t\toh = Math.min(oh, h);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tw = tmp;
\t\t\t\t}

\t\t\t\t// Handles words that are longer than the given wrapping width
\t\t\t\tif (wrap)
\t\t\t\t{
\t\t\t\t\tdiv.style.width = w + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Simulates max-height in quirks
\t\t\t\tif (mxClient.IS_QUIRKS && (clip || overflow == 'width') && oh > h)
\t\t\t\t{
\t\t\t\t\toh = h;
\t\t\t\t\t
\t\t\t\t\t// Quirks does not support maxHeight
\t\t\t\t\tdiv.style.height = oh + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\th = oh;

\t\t\t\tvar top_fix = (h - h * cos + w * -sin) / 2 - real_sin * w * (dx + 0.5) + real_cos * h * (dy + 0.5);
\t\t\t\tvar left_fix = (w - w * cos + h * -sin) / 2 + real_cos * w * (dx + 0.5) + real_sin * h * (dy + 0.5);

\t\t\t\tif (abs.nodeName == 'group' && this.root.nodeName == 'DIV')
\t\t\t\t{
\t\t\t\t\t// Workaround for bug where group gets moved away if left and top are non-zero in IE8 standards
\t\t\t\t\tvar pos = this.createElement('div');
\t\t\t\t\tpos.style.display = 'inline-block';
\t\t\t\t\tpos.style.position = 'absolute';
\t\t\t\t\tpos.style.left = this.format(x + (left_fix - w / 2) * s.scale) + 'px';
\t\t\t\t\tpos.style.top = this.format(y + (top_fix - h / 2) * s.scale) + 'px';
\t\t\t\t\t
\t\t\t\t\tabs.parentNode.appendChild(pos);
\t\t\t\t\tpos.appendChild(abs);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar sc = (document.documentMode == 8 && !mxClient.IS_EM) ? 1 : s.scale;
\t\t\t\t\t
\t\t\t\t\tabs.style.left = this.format(x + (left_fix - w / 2) * sc) + 'px';
\t\t\t\t\tabs.style.top = this.format(y + (top_fix - h / 2) * sc) + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\t// KNOWN: Rotated text rendering quality is bad for IE9 quirks
\t\t\t\tinner.style.filter = \"progid:DXImageTransform.Microsoft.Matrix(M11=\"+real_cos+\", M12=\"+
\t\t\t\t\treal_sin+\", M21=\"+(-real_sin)+\", M22=\"+real_cos+\", sizingMethod='auto expand')\";
\t\t\t\tinner.style.backgroundColor = this.rotatedHtmlBackground;
\t\t\t\t
\t\t\t\tif (this.state.alpha < 1)
\t\t\t\t{
\t\t\t\t\tinner.style.filter += 'alpha(opacity=' + (this.state.alpha * 100) + ')';
\t\t\t\t}

\t\t\t\t// Restore parent node for DIV
\t\t\t\tinner.appendChild(div);
\t\t\t\tdiv.style.position = '';
\t\t\t\tdiv.style.visibility = '';
\t\t\t}
\t\t\telse if (document.documentMode != 8 || mxClient.IS_EM)
\t\t\t{
\t\t\t\tdiv.style.verticalAlign = 'top';
\t\t\t\t
\t\t\t\tif (this.state.alpha < 1)
\t\t\t\t{
\t\t\t\t\tabs.style.filter = 'alpha(opacity=' + (this.state.alpha * 100) + ')';
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Adds div to document to measure size
\t\t\t\tvar divParent = div.parentNode;
\t\t\t\tdiv.style.visibility = 'hidden';
\t\t\t\tdocument.body.appendChild(div);
\t\t\t\t
\t\t\t\tw = div.offsetWidth;
\t\t\t\tvar oh = div.offsetHeight;
\t\t\t\t
\t\t\t\t// Simulates max-height in quirks
\t\t\t\tif (mxClient.IS_QUIRKS && clip && oh > h)
\t\t\t\t{
\t\t\t\t\toh = h;
\t\t\t\t\t
\t\t\t\t\t// Quirks does not support maxHeight
\t\t\t\t\tdiv.style.height = oh + 'px';
\t\t\t\t}
\t\t\t\t
\t\t\t\th = oh;
\t\t\t\t
\t\t\t\tdiv.style.visibility = '';
\t\t\t\tdivParent.appendChild(div);
\t\t\t\t
\t\t\t\tabs.style.left = this.format(x + w * dx * this.state.scale) + 'px';
\t\t\t\tabs.style.top = this.format(y + h * dy * this.state.scale) + 'px';
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (this.state.alpha < 1)
\t\t\t\t{
\t\t\t\t\tdiv.style.filter = 'alpha(opacity=' + (this.state.alpha * 100) + ')';
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Faster rendering in IE8 without offsetWidth/Height
\t\t\t\tbox.style.left = (dx * 100) + '%';
\t\t\t\tbox.style.top = (dy * 100) + '%';
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tthis.plainText(x, y, w, h, mxUtils.htmlEntities(str, false), align, valign, wrap, format, overflow, clip, rotation, dir);
\t\t}
\t}
};

/**
 * Function: plainText
 * 
 * Paints the outline of the current path.
 */
mxVmlCanvas2D.prototype.plainText = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
{
\t// TextDirection is ignored since this code is not used (format is always HTML in the text function)
\tvar s = this.state;
\tx = (x + s.dx) * s.scale;
\ty = (y + s.dy) * s.scale;
\t
\tvar node = this.createVmlElement('shape');
\tnode.style.width = '1px';
\tnode.style.height = '1px';
\tnode.stroked = 'false';

\tvar fill = this.createVmlElement('fill');
\tfill.color = s.fontColor;
\tfill.opacity = (s.alpha * 100) + '%';
\tnode.appendChild(fill);
\t
\tvar path = this.createVmlElement('path');
\tpath.textpathok = 'true';
\tpath.v = 'm ' + this.format(0) + ' ' + this.format(0) + ' l ' + this.format(1) + ' ' + this.format(0);
\t
\tnode.appendChild(path);
\t
\t// KNOWN: Font family and text decoration ignored
\tvar tp = this.createVmlElement('textpath');
\ttp.style.cssText = 'v-text-align:' + align;
\ttp.style.align = align;
\ttp.style.fontFamily = s.fontFamily;
\ttp.string = str;
\ttp.on = 'true';
\t
\t// Scale via fontsize instead of node.style.zoom for correct offsets in IE8
\tvar size = s.fontSize * s.scale / this.vmlScale;
\ttp.style.fontSize = size + 'px';
\t
\t// Bold
\tif ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\ttp.style.fontWeight = 'bold';
\t}
\t
\t// Italic
\tif ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\ttp.style.fontStyle = 'italic';
\t}

\t// Underline
\tif ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\ttp.style.textDecoration = 'underline';
\t}

\tvar lines = str.split('\\n');
\tvar textHeight = size + (lines.length - 1) * size * mxConstants.LINE_HEIGHT;
\tvar dx = 0;
\tvar dy = 0;

\tif (valign == mxConstants.ALIGN_BOTTOM)
\t{
\t\tdy = - textHeight / 2;
\t}
\telse if (valign != mxConstants.ALIGN_MIDDLE) // top
\t{
\t\tdy = textHeight / 2;
\t}

\tif (rotation != null)
\t{
\t\tnode.style.rotation = rotation;
\t\tvar rad = rotation * (Math.PI / 180);
\t\tdx = Math.sin(rad) * dy;
\t\tdy = Math.cos(rad) * dy;
\t}

\t// FIXME: Clipping is relative to bounding box
\t/*if (clip)
\t{
\t\tnode.style.clip = 'rect(0px ' + this.format(w) + 'px ' + this.format(h) + 'px 0px)';
\t}*/
\t
\tnode.appendChild(tp);
\tnode.style.left = this.format(x - dx) + 'px';
\tnode.style.top = this.format(y + dy) + 'px';
\t
\tthis.root.appendChild(node);
};

/**
 * Function: stroke
 * 
 * Paints the outline of the current path.
 */
mxVmlCanvas2D.prototype.stroke = function()
{
\tthis.addNode(false, true);
};

/**
 * Function: fill
 * 
 * Fills the current path.
 */
mxVmlCanvas2D.prototype.fill = function()
{
\tthis.addNode(true, false);
};

/**
 * Function: fillAndStroke
 * 
 * Fills and paints the outline of the current path.
 */
mxVmlCanvas2D.prototype.fillAndStroke = function()
{
\tthis.addNode(true, true);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGuide
 *
 * Implements the alignment of selection cells to other cells in the graph.
 * 
 * Constructor: mxGuide
 * 
 * Constructs a new guide object.
 */
function mxGuide(graph, states)
{
\tthis.graph = graph;
\tthis.setStates(states);
};

/**
 * Variable: graph
 *
 * Reference to the enclosing <mxGraph> instance.
 */
mxGuide.prototype.graph = null;

/**
 * Variable: states
 * 
 * Contains the <mxCellStates> that are used for alignment.
 */
mxGuide.prototype.states = null;

/**
 * Variable: horizontal
 *
 * Specifies if horizontal guides are enabled. Default is true.
 */
mxGuide.prototype.horizontal = true;

/**
 * Variable: vertical
 *
 * Specifies if vertical guides are enabled. Default is true.
 */
mxGuide.prototype.vertical = true;

/**
 * Variable: guideX
 *
 * Holds the <mxShape> for the horizontal guide.
 */
mxGuide.prototype.guideX = null;

/**
 * Variable: guideY
 *
 * Holds the <mxShape> for the vertical guide.
 */
mxGuide.prototype.guideY = null;

/**
 * Variable: rounded
 *
 * Specifies if rounded coordinates should be used. Default is false.
 */
mxGuide.prototype.rounded = false;

/**
 * Variable: tolerance
 * 
 * Default tolerance in px if grid is disabled. Default is 2.
 */
mxGuide.prototype.tolerance = 2;

/**
 * Function: setStates
 * 
 * Sets the <mxCellStates> that should be used for alignment.
 */
mxGuide.prototype.setStates = function(states)
{
\tthis.states = states;
};

/**
 * Function: isEnabledForEvent
 * 
 * Returns true if the guide should be enabled for the given native event. This
 * implementation always returns true.
 */
mxGuide.prototype.isEnabledForEvent = function(evt)
{
\treturn true;
};

/**
 * Function: getGuideTolerance
 * 
 * Returns the tolerance for the guides. Default value is gridSize / 2.
 */
mxGuide.prototype.getGuideTolerance = function(gridEnabled)
{
\treturn (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance;
};

/**
 * Function: createGuideShape
 * 
 * Returns the mxShape to be used for painting the respective guide. This
 * implementation returns a new, dashed and crisp <mxPolyline> using
 * <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format.
 * 
 * Parameters:
 * 
 * horizontal - Boolean that specifies which guide should be created.
 */
mxGuide.prototype.createGuideShape = function(horizontal)
{
\tvar guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH);
\tguide.isDashed = true;
\t
\treturn guide;
};

/**
 * Function: isStateIgnored
 * 
 * Returns true if the given state should be ignored.
 */
mxGuide.prototype.isStateIgnored = function(state)
{
\treturn false;
};

/**
 * Function: move
 * 
 * Moves the <bounds> by the given <mxPoint> and returnt the snapped point.
 */
mxGuide.prototype.move = function(bounds, delta, gridEnabled, clone)
{
\tif (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null)
\t{
\t\tvar scale = this.graph.getView().scale;
\t\tvar tt = this.getGuideTolerance(gridEnabled) * scale;
\t\tvar b = bounds.clone();
\t\tb.x += delta.x;
\t\tb.y += delta.y;
\t\tvar overrideX = false;
\t\tvar stateX = null;
\t\tvar valueX = null;
\t\tvar overrideY = false;
\t\tvar stateY = null;
\t\tvar valueY = null;
\t\tvar ttX = tt;
\t\tvar ttY = tt;
\t\tvar left = b.x;
\t\tvar right = b.x + b.width;
\t\tvar center = b.getCenterX();
\t\tvar top = b.y;
\t\tvar bottom = b.y + b.height;
\t\tvar middle = b.getCenterY();
\t
\t\t// Snaps the left, center and right to the given x-coordinate
\t\tfunction snapX(x, state, centerAlign)
\t\t{
\t\t\tvar override = false;
\t\t\t
\t\t\tif (centerAlign && Math.abs(x - center) < ttX)
\t\t\t{
\t\t\t\tdelta.x = x - bounds.getCenterX();
\t\t\t\tttX = Math.abs(x - center);
\t\t\t\toverride = true;
\t\t\t}
\t\t\telse if (!centerAlign)
\t\t\t{
\t\t\t\tif (Math.abs(x - left) < ttX)
\t\t\t\t{
\t\t\t\t\tdelta.x = x - bounds.x;
\t\t\t\t\tttX = Math.abs(x - left);
\t\t\t\t\toverride = true;
\t\t\t\t}
\t\t\t\telse if (Math.abs(x - right) < ttX)
\t\t\t\t{
\t\t\t\t\tdelta.x = x - bounds.x - bounds.width;
\t\t\t\t\tttX = Math.abs(x - right);
\t\t\t\t\toverride = true;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (override)
\t\t\t{
\t\t\t\tstateX = state;
\t\t\t\tvalueX = x;
\t\t\t\t
\t\t\t\tif (this.guideX == null)
\t\t\t\t{
\t\t\t\t\tthis.guideX = this.createGuideShape(true);
\t\t\t\t\t
\t\t\t\t\t// Makes sure to use either VML or SVG shapes in order to implement
\t\t\t\t\t// event-transparency on the background area of the rectangle since
\t\t\t\t\t// HTML shapes do not let mouseevents through even when transparent
\t\t\t\t\tthis.guideX.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\t\t\t\tmxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\t\t\t\t\tthis.guideX.pointerEvents = false;
\t\t\t\t\tthis.guideX.init(this.graph.getView().getOverlayPane());
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\toverrideX = overrideX || override;
\t\t};
\t\t
\t\t// Snaps the top, middle or bottom to the given y-coordinate
\t\tfunction snapY(y, state, centerAlign)
\t\t{
\t\t\tvar override = false;
\t\t\t
\t\t\tif (centerAlign && Math.abs(y - middle) < ttY)
\t\t\t{
\t\t\t\tdelta.y = y - bounds.getCenterY();
\t\t\t\tttY = Math.abs(y -  middle);
\t\t\t\toverride = true;
\t\t\t}
\t\t\telse if (!centerAlign)
\t\t\t{
\t\t\t\tif (Math.abs(y - top) < ttY)
\t\t\t\t{
\t\t\t\t\tdelta.y = y - bounds.y;
\t\t\t\t\tttY = Math.abs(y - top);
\t\t\t\t\toverride = true;
\t\t\t\t}
\t\t\t\telse if (Math.abs(y - bottom) < ttY)
\t\t\t\t{
\t\t\t\t\tdelta.y = y - bounds.y - bounds.height;
\t\t\t\t\tttY = Math.abs(y - bottom);
\t\t\t\t\toverride = true;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (override)
\t\t\t{
\t\t\t\tstateY = state;
\t\t\t\tvalueY = y;
\t\t\t\t
\t\t\t\tif (this.guideY == null)
\t\t\t\t{
\t\t\t\t\tthis.guideY = this.createGuideShape(false);
\t\t\t\t\t
\t\t\t\t\t// Makes sure to use either VML or SVG shapes in order to implement
\t\t\t\t\t// event-transparency on the background area of the rectangle since
\t\t\t\t\t// HTML shapes do not let mouseevents through even when transparent
\t\t\t\t\tthis.guideY.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\t\t\t\tmxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\t\t\t\t\tthis.guideY.pointerEvents = false;
\t\t\t\t\tthis.guideY.init(this.graph.getView().getOverlayPane());
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\toverrideY = overrideY || override;
\t\t};
\t\t
\t\tfor (var i = 0; i < this.states.length; i++)
\t\t{
\t\t\tvar state =  this.states[i];
\t\t\t
\t\t\tif (state != null && !this.isStateIgnored(state))
\t\t\t{
\t\t\t\t// Align x
\t\t\t\tif (this.horizontal)
\t\t\t\t{
\t\t\t\t\tsnapX.call(this, state.getCenterX(), state, true);
\t\t\t\t\tsnapX.call(this, state.x, state, false);
\t\t\t\t\tsnapX.call(this, state.x + state.width, state, false);
\t\t\t\t\t
\t\t\t\t\t// Aligns left and right of shape to center of page
\t\t\t\t\tif (state.cell == null)
\t\t\t\t\t{
\t\t\t\t\t\tsnapX.call(this, state.getCenterX(), state, false);
\t\t\t\t\t}
\t\t\t\t}
\t
\t\t\t\t// Align y
\t\t\t\tif (this.vertical)
\t\t\t\t{
\t\t\t\t\tsnapY.call(this, state.getCenterY(), state, true);
\t\t\t\t\tsnapY.call(this, state.y, state, false);
\t\t\t\t\tsnapY.call(this, state.y + state.height, state, false);
\t\t\t\t\t
\t\t\t\t\t// Aligns left and right of shape to center of page
\t\t\t\t\tif (state.cell == null)
\t\t\t\t\t{
\t\t\t\t\t\tsnapY.call(this, state.getCenterY(), state, false);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Moves cells to the raster if not aligned
\t\tthis.graph.snapDelta(delta, bounds, !gridEnabled, overrideX, overrideY);
\t\tdelta = this.getDelta(bounds, stateX, delta.x, stateY, delta.y)
\t\t
\t\t// Redraws the guides
\t\tvar c = this.graph.container;
\t\t
\t\tif (!overrideX && this.guideX != null)
\t\t{
\t\t\tthis.guideX.node.style.visibility = 'hidden';
\t\t}
\t\telse if (this.guideX != null)
\t\t{
\t\t\tvar minY = null;
        \tvar maxY = null;
        \t
\t\t\tif (stateX != null && bounds != null)
\t\t\t{
\t\t\t\tminY = Math.min(bounds.y + delta.y - this.graph.panDy, stateX.y);
\t\t\t\tmaxY = Math.max(bounds.y + bounds.height + delta.y - this.graph.panDy, stateX.y + stateX.height);
\t\t\t}
\t\t\t
\t\t\tif (minY != null && maxY != null)
\t\t\t{
\t\t\t\tthis.guideX.points = [new mxPoint(valueX, minY), new mxPoint(valueX, maxY)];
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.guideX.points = [new mxPoint(valueX, -this.graph.panDy),
\t\t\t\t\tnew mxPoint(valueX, c.scrollHeight - 3 - this.graph.panDy)];
\t\t\t}
\t\t\t
\t\t\tthis.guideX.stroke = this.getGuideColor(stateX, true);
\t\t\tthis.guideX.node.style.visibility = 'visible';
\t\t\tthis.guideX.redraw();
\t\t}
\t\t
\t\tif (!overrideY && this.guideY != null)
\t\t{
\t\t\tthis.guideY.node.style.visibility = 'hidden';
\t\t}
\t\telse if (this.guideY != null)
\t\t{
\t\t\tvar minX = null;
        \tvar maxX = null;
        \t
\t\t\tif (stateY != null && bounds != null)
\t\t\t{
\t\t\t\tminX = Math.min(bounds.x + delta.x - this.graph.panDx, stateY.x);
\t\t\t\tmaxX = Math.max(bounds.x + bounds.width + delta.x - this.graph.panDx, stateY.x + stateY.width);
\t\t\t}
\t\t\t
\t\t\tif (minX != null && maxX != null)
\t\t\t{
\t\t\t\tthis.guideY.points = [new mxPoint(minX, valueY), new mxPoint(maxX, valueY)];
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.guideY.points = [new mxPoint(-this.graph.panDx, valueY),
\t\t\t\t\tnew mxPoint(c.scrollWidth - 3 - this.graph.panDx, valueY)];
\t\t\t}
\t\t\t
\t\t\tthis.guideY.stroke = this.getGuideColor(stateY, false);
\t\t\tthis.guideY.node.style.visibility = 'visible';
\t\t\tthis.guideY.redraw();
\t\t}
\t}
\t
\treturn delta;
};

/**
 * Function: getDelta
 * 
 * Rounds to pixels for virtual states (eg. page guides)
 */
mxGuide.prototype.getDelta = function(bounds, stateX, dx, stateY, dy)
{
\tvar s = this.graph.view.scale;
\t
\tif (this.rounded || (stateX != null && stateX.cell == null))
\t{
\t\tdx = Math.round((bounds.x + dx) / s) * s - bounds.x;
\t}

\tif (this.rounded || (stateY != null && stateY.cell == null))
\t{
\t\tdy = Math.round((bounds.y + dy) / s) * s - bounds.y;
\t}
\t
\treturn new mxPoint(dx, dy);
};

/**
 * Function: getGuideColor
 * 
 * Returns the color for the given state.
 */
mxGuide.prototype.getGuideColor = function(state, horizontal)
{
\treturn mxConstants.GUIDE_COLOR;
};

/**
 * Function: hide
 * 
 * Hides all current guides.
 */
mxGuide.prototype.hide = function()
{
\tthis.setVisible(false);
};

/**
 * Function: setVisible
 * 
 * Shows or hides the current guides.
 */
mxGuide.prototype.setVisible = function(visible)
{
\tif (this.guideX != null)
\t{
\t\tthis.guideX.node.style.visibility = (visible) ? 'visible' : 'hidden';
\t}
\t
\tif (this.guideY != null)
\t{
\t\tthis.guideY.node.style.visibility = (visible) ? 'visible' : 'hidden';
\t}
};

/**
 * Function: destroy
 * 
 * Destroys all resources that this object uses.
 */
mxGuide.prototype.destroy = function()
{
\tif (this.guideX != null)
\t{
\t\tthis.guideX.destroy();
\t\tthis.guideX = null;
\t}
\t
\tif (this.guideY != null)
\t{
\t\tthis.guideY.destroy();
\t\tthis.guideY = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxShape
 *
 * Base class for all shapes. A shape in mxGraph is a
 * separate implementation for SVG, VML and HTML. Which
 * implementation to use is controlled by the <dialect>
 * property which is assigned from within the <mxCellRenderer>
 * when the shape is created. The dialect must be assigned
 * for a shape, and it does normally depend on the browser and
 * the confiuration of the graph (see <mxGraph> rendering hint).
 *
 * For each supported shape in SVG and VML, a corresponding
 * shape exists in mxGraph, namely for text, image, rectangle,
 * rhombus, ellipse and polyline. The other shapes are a
 * combination of these shapes (eg. label and swimlane)
 * or they consist of one or more (filled) path objects
 * (eg. actor and cylinder). The HTML implementation is
 * optional but may be required for a HTML-only view of
 * the graph.
 *
 * Custom Shapes:
 *
 * To extend from this class, the basic code looks as follows.
 * In the special case where the custom shape consists only of
 * one filled region or one filled region and an additional stroke
 * the <mxActor> and <mxCylinder> should be subclassed,
 * respectively.
 *
 * (code)
 * function CustomShape() { }
 * 
 * CustomShape.prototype = new mxShape();
 * CustomShape.prototype.constructor = CustomShape; 
 * (end)
 *
 * To register a custom shape in an existing graph instance,
 * one must register the shape under a new name in the graph's
 * cell renderer as follows:
 *
 * (code)
 * mxCellRenderer.registerShape('customShape', CustomShape);
 * (end)
 *
 * The second argument is the name of the constructor.
 *
 * In order to use the shape you can refer to the given name above
 * in a stylesheet. For example, to change the shape for the default
 * vertex style, the following code is used:
 *
 * (code)
 * var style = graph.getStylesheet().getDefaultVertexStyle();
 * style[mxConstants.STYLE_SHAPE] = 'customShape';
 * (end)
 * 
 * Constructor: mxShape
 *
 * Constructs a new shape.
 */
function mxShape(stencil)
{
\tthis.stencil = stencil;
\tthis.initStyles();
};

/**
 * Variable: dialect
 *
 * Holds the dialect in which the shape is to be painted.
 * This can be one of the DIALECT constants in <mxConstants>.
 */
mxShape.prototype.dialect = null;

/**
 * Variable: scale
 *
 * Holds the scale in which the shape is being painted.
 */
mxShape.prototype.scale = 1;

/**
 * Variable: antiAlias
 * 
 * Rendering hint for configuring the canvas.
 */
mxShape.prototype.antiAlias = true;

/**
 * Variable: minSvgStrokeWidth
 * 
 * Minimum stroke width for SVG output.
 */
mxShape.prototype.minSvgStrokeWidth = 1;

/**
 * Variable: bounds
 *
 * Holds the <mxRectangle> that specifies the bounds of this shape.
 */
mxShape.prototype.bounds = null;

/**
 * Variable: points
 *
 * Holds the array of <mxPoints> that specify the points of this shape.
 */
mxShape.prototype.points = null;

/**
 * Variable: node
 *
 * Holds the outermost DOM node that represents this shape.
 */
mxShape.prototype.node = null;
 
/**
 * Variable: state
 * 
 * Optional reference to the corresponding <mxCellState>.
 */
mxShape.prototype.state = null;

/**
 * Variable: style
 *
 * Optional reference to the style of the corresponding <mxCellState>.
 */
mxShape.prototype.style = null;

/**
 * Variable: boundingBox
 *
 * Contains the bounding box of the shape, that is, the smallest rectangle
 * that includes all pixels of the shape.
 */
mxShape.prototype.boundingBox = null;

/**
 * Variable: stencil
 *
 * Holds the <mxStencil> that defines the shape.
 */
mxShape.prototype.stencil = null;

/**
 * Variable: svgStrokeTolerance
 *
 * Event-tolerance for SVG strokes (in px). Default is 8. This is only passed
 * to the canvas in <createSvgCanvas> if <pointerEvents> is true.
 */
mxShape.prototype.svgStrokeTolerance = 8;

/**
 * Variable: pointerEvents
 * 
 * Specifies if pointer events should be handled. Default is true.
 */
mxShape.prototype.pointerEvents = true;

/**
 * Variable: svgPointerEvents
 * 
 * Specifies if pointer events should be handled. Default is true.
 */
mxShape.prototype.svgPointerEvents = 'all';

/**
 * Variable: shapePointerEvents
 * 
 * Specifies if pointer events outside of shape should be handled. Default
 * is false.
 */
mxShape.prototype.shapePointerEvents = false;

/**
 * Variable: stencilPointerEvents
 * 
 * Specifies if pointer events outside of stencils should be handled. Default
 * is false. Set this to true for backwards compatibility with the 1.x branch.
 */
mxShape.prototype.stencilPointerEvents = false;

/**
 * Variable: vmlScale
 * 
 * Scale for improving the precision of VML rendering. Default is 1.
 */
mxShape.prototype.vmlScale = 1;

/**
 * Variable: outline
 * 
 * Specifies if the shape should be drawn as an outline. This disables all
 * fill colors and can be used to disable other drawing states that should
 * not be painted for outlines. Default is false. This should be set before
 * calling <apply>.
 */
mxShape.prototype.outline = false;

/**
 * Variable: visible
 * 
 * Specifies if the shape is visible. Default is true.
 */
mxShape.prototype.visible = true;

/**
 * Variable: useSvgBoundingBox
 * 
 * Allows to use the SVG bounding box in SVG. Default is false for performance
 * reasons.
 */
mxShape.prototype.useSvgBoundingBox = false;

/**
 * Function: init
 *
 * Initializes the shape by creaing the DOM node using <create>
 * and adding it into the given container.
 *
 * Parameters:
 *
 * container - DOM node that will contain the shape.
 */
mxShape.prototype.init = function(container)
{
\tif (this.node == null)
\t{
\t\tthis.node = this.create(container);
\t\t
\t\tif (container != null)
\t\t{
\t\t\tcontainer.appendChild(this.node);
\t\t}
\t}
};

/**
 * Function: initStyles
 *
 * Sets the styles to their default values.
 */
mxShape.prototype.initStyles = function(container)
{
\tthis.strokewidth = 1;
\tthis.rotation = 0;
\tthis.opacity = 100;
\tthis.fillOpacity = 100;
\tthis.strokeOpacity = 100;
\tthis.flipH = false;
\tthis.flipV = false;
};

/**
 * Function: isParseVml
 * 
 * Specifies if any VML should be added via insertAdjacentHtml to the DOM. This
 * is only needed in IE8 and only if the shape contains VML markup. This method
 * returns true.
 */
mxShape.prototype.isParseVml = function()
{
\treturn true;
};

/**
 * Function: isHtmlAllowed
 * 
 * Returns true if HTML is allowed for this shape. This implementation always
 * returns false.
 */
mxShape.prototype.isHtmlAllowed = function()
{
\treturn false;
};

/**
 * Function: getSvgScreenOffset
 * 
 * Returns 0, or 0.5 if <strokewidth> % 2 == 1.
 */
mxShape.prototype.getSvgScreenOffset = function()
{
\tvar sw = this.stencil && this.stencil.strokewidth != 'inherit' ? Number(this.stencil.strokewidth) : this.strokewidth;
\t
\treturn (mxUtils.mod(Math.max(1, Math.round(sw * this.scale)), 2) == 1) ? 0.5 : 0;
};

/**
 * Function: create
 *
 * Creates and returns the DOM node(s) for the shape in
 * the given container. This implementation invokes
 * <createSvg>, <createHtml> or <createVml> depending
 * on the <dialect> and style settings.
 *
 * Parameters:
 *
 * container - DOM node that will contain the shape.
 */
mxShape.prototype.create = function(container)
{
\tvar node = null;
\t
\tif (container != null && container.ownerSVGElement != null)
\t{
\t\tnode = this.createSvg(container);
\t}
\telse if (document.documentMode == 8 || !mxClient.IS_VML ||
\t\t(this.dialect != mxConstants.DIALECT_VML && this.isHtmlAllowed()))
\t{
\t\tnode = this.createHtml(container);
\t}
\telse
\t{
\t\tnode = this.createVml(container);
\t}
\t
\treturn node;
};

/**
 * Function: createSvg
 *
 * Creates and returns the SVG node(s) to represent this shape.
 */
mxShape.prototype.createSvg = function()
{
\treturn document.createElementNS(mxConstants.NS_SVG, 'g');
};

/**
 * Function: createVml
 *
 * Creates and returns the VML node to represent this shape.
 */
mxShape.prototype.createVml = function()
{
\tvar node = document.createElement(mxClient.VML_PREFIX + ':group');
\tnode.style.position = 'absolute';
\t
\treturn node;
};

/**
 * Function: createHtml
 *
 * Creates and returns the HTML DOM node(s) to represent
 * this shape. This implementation falls back to <createVml>
 * so that the HTML creation is optional.
 */
mxShape.prototype.createHtml = function()
{
\tvar node = document.createElement('div');
\tnode.style.position = 'absolute';
\t
\treturn node;
};

/**
 * Function: reconfigure
 *
 * Reconfigures this shape. This will update the colors etc in
 * addition to the bounds or points.
 */
mxShape.prototype.reconfigure = function()
{
\tthis.redraw();
};

/**
 * Function: redraw
 *
 * Creates and returns the SVG node(s) to represent this shape.
 */
mxShape.prototype.redraw = function()
{
\tthis.updateBoundsFromPoints();
\t
\tif (this.visible && this.checkBounds())
\t{
\t\tthis.node.style.visibility = 'visible';
\t\tthis.clear();
\t\t
\t\tif (this.node.nodeName == 'DIV' && (this.isHtmlAllowed() || !mxClient.IS_VML))
\t\t{
\t\t\tthis.redrawHtmlShape();
\t\t}
\t\telse
\t\t{\t
\t\t\tthis.redrawShape();
\t\t}

\t\tthis.updateBoundingBox();
\t}
\telse
\t{
\t\tthis.node.style.visibility = 'hidden';
\t\tthis.boundingBox = null;
\t}
};

/**
 * Function: clear
 * 
 * Removes all child nodes and resets all CSS.
 */
mxShape.prototype.clear = function()
{
\tif (this.node.ownerSVGElement != null)
\t{
\t\twhile (this.node.lastChild != null)
\t\t{
\t\t\tthis.node.removeChild(this.node.lastChild);
\t\t}
\t}
\telse
\t{
\t\tthis.node.style.cssText = 'position:absolute;' + ((this.cursor != null) ?
\t\t\t('cursor:' + this.cursor + ';') : '');
\t\tthis.node.innerHTML = '';
\t}
};

/**
 * Function: updateBoundsFromPoints
 * 
 * Updates the bounds based on the points.
 */
mxShape.prototype.updateBoundsFromPoints = function()
{
\tvar pts = this.points;
\t
\tif (pts != null && pts.length > 0 && pts[0] != null)
\t{
\t\tthis.bounds = new mxRectangle(Number(pts[0].x), Number(pts[0].y), 1, 1);
\t\t
\t\tfor (var i = 1; i < this.points.length; i++)
\t\t{
\t\t\tif (pts[i] != null)
\t\t\t{
\t\t\t\tthis.bounds.add(new mxRectangle(Number(pts[i].x), Number(pts[i].y), 1, 1));
\t\t\t}
\t\t}
\t}
};

/**
 * Function: getLabelBounds
 * 
 * Returns the <mxRectangle> for the label bounds of this shape, based on the
 * given scaled and translated bounds of the shape. This method should not
 * change the rectangle in-place. This implementation returns the given rect.
 */
mxShape.prototype.getLabelBounds = function(rect)
{
\tvar d = mxUtils.getValue(this.style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
\tvar bounds = rect;
\t
\t// Normalizes argument for getLabelMargins hook
\tif (d != mxConstants.DIRECTION_SOUTH && d != mxConstants.DIRECTION_NORTH &&
\t\tthis.state != null && this.state.text != null &&
\t\tthis.state.text.isPaintBoundsInverted())
\t{
\t\tbounds = bounds.clone();
\t\tvar tmp = bounds.width;
\t\tbounds.width = bounds.height;
\t\tbounds.height = tmp;
\t}
\t\t
\tvar m = this.getLabelMargins(bounds);
\t
\tif (m != null)
\t{
\t\tvar flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, false) == '1';
\t\tvar flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, false) == '1';
\t\t
\t\t// Handles special case for vertical labels
\t\tif (this.state != null && this.state.text != null &&
\t\t\tthis.state.text.isPaintBoundsInverted())
\t\t{
\t\t\tvar tmp = m.x;
\t\t\tm.x = m.height;
\t\t\tm.height = m.width;
\t\t\tm.width = m.y;
\t\t\tm.y = tmp;

\t\t\ttmp = flipH;
\t\t\tflipH = flipV;
\t\t\tflipV = tmp;
\t\t}
\t\t
\t\treturn mxUtils.getDirectedBounds(rect, m, this.style, flipH, flipV);
\t}
\t
\treturn rect;
};

/**
 * Function: getLabelMargins
 * 
 * Returns the scaled top, left, bottom and right margin to be used for
 * computing the label bounds as an <mxRectangle>, where the bottom and right
 * margin are defined in the width and height of the rectangle, respectively.
 */
mxShape.prototype.getLabelMargins= function(rect)
{
\treturn null;
};

/**
 * Function: checkBounds
 * 
 * Returns true if the bounds are not null and all of its variables are numeric.
 */
mxShape.prototype.checkBounds = function()
{
\treturn (!isNaN(this.scale) && isFinite(this.scale) && this.scale > 0 &&
\t\t\tthis.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
\t\t\t!isNaN(this.bounds.width) && !isNaN(this.bounds.height) &&
\t\t\tthis.bounds.width > 0 && this.bounds.height > 0);
};

/**
 * Function: createVmlGroup
 *
 * Returns the temporary element used for rendering in IE8 standards mode.
 */
mxShape.prototype.createVmlGroup = function()
{
\tvar node = document.createElement(mxClient.VML_PREFIX + ':group');
\tnode.style.position = 'absolute';
\tnode.style.width = this.node.style.width;
\tnode.style.height = this.node.style.height;
\t
\treturn node;
};

/**
 * Function: redrawShape
 *
 * Updates the SVG or VML shape.
 */
mxShape.prototype.redrawShape = function()
{
\tvar canvas = this.createCanvas();
\t
\tif (canvas != null)
\t{
\t\t// Specifies if events should be handled
\t\tcanvas.pointerEvents = this.pointerEvents;
\t
\t\tthis.beforePaint(canvas);
\t\tthis.paint(canvas);
\t\tthis.afterPaint(canvas);
\t
\t\tif (this.node != canvas.root)
\t\t{
\t\t\t// Forces parsing in IE8 standards mode - slow! avoid
\t\t\tthis.node.insertAdjacentHTML('beforeend', canvas.root.outerHTML);
\t\t}
\t
\t\tif (this.node.nodeName == 'DIV' && document.documentMode == 8)
\t\t{
\t\t\t// Makes DIV transparent to events for IE8 in IE8 standards
\t\t\t// mode (Note: Does not work for IE9 in IE8 standards mode
\t\t\t// and not for IE11 in enterprise mode)
\t\t\tthis.node.style.filter = '';
\t\t\t
\t\t\t// Adds event transparency in IE8 standards
\t\t\tmxUtils.addTransparentBackgroundFilter(this.node);
\t\t}
\t\t
\t\tthis.destroyCanvas(canvas);
\t}
};

/**
 * Function: createCanvas
 * 
 * Creates a new canvas for drawing this shape. May return null.
 */
mxShape.prototype.createCanvas = function()
{
\tvar canvas = null;
\t
\t// LATER: Check if reusing existing DOM nodes improves performance
\tif (this.node.ownerSVGElement != null)
\t{
\t\tcanvas = this.createSvgCanvas();
\t}
\telse if (mxClient.IS_VML)
\t{
\t\tthis.updateVmlContainer();
\t\tcanvas = this.createVmlCanvas();
\t}
\t
\tif (canvas != null && this.outline)
\t{
\t\tcanvas.setStrokeWidth(this.strokewidth);
\t\tcanvas.setStrokeColor(this.stroke);
\t\t
\t\tif (this.isDashed != null)
\t\t{
\t\t\tcanvas.setDashed(this.isDashed);
\t\t}
\t\t
\t\tcanvas.setStrokeWidth = function() {};
\t\tcanvas.setStrokeColor = function() {};
\t\tcanvas.setFillColor = function() {};
\t\tcanvas.setGradient = function() {};
\t\tcanvas.setDashed = function() {};
\t\tcanvas.text = function() {};
\t}

\treturn canvas;
};

/**
 * Function: createSvgCanvas
 * 
 * Creates and returns an <mxSvgCanvas2D> for rendering this shape.
 */
mxShape.prototype.createSvgCanvas = function()
{
\tvar canvas = new mxSvgCanvas2D(this.node, false);
\tcanvas.strokeTolerance = (this.pointerEvents) ? this.svgStrokeTolerance : 0;
\tcanvas.pointerEventsValue = this.svgPointerEvents;
\tvar off = this.getSvgScreenOffset();

\tif (off != 0)
\t{
\t\tthis.node.setAttribute('transform', 'translate(' + off + ',' + off + ')');
\t}
\telse
\t{
\t\tthis.node.removeAttribute('transform');
\t}

\tcanvas.minStrokeWidth = this.minSvgStrokeWidth;
\t
\tif (!this.antiAlias)
\t{
\t\t// Rounds all numbers in the SVG output to integers
\t\tcanvas.format = function(value)
\t\t{
\t\t\treturn Math.round(parseFloat(value));
\t\t};
\t}
\t
\treturn canvas;
};

/**
 * Function: createVmlCanvas
 * 
 * Creates and returns an <mxVmlCanvas2D> for rendering this shape.
 */
mxShape.prototype.createVmlCanvas = function()
{
\t// Workaround for VML rendering bug in IE8 standards mode
\tvar node = (document.documentMode == 8 && this.isParseVml()) ? this.createVmlGroup() : this.node;
\tvar canvas = new mxVmlCanvas2D(node, false);
\t
\tif (node.tagUrn != '')
\t{
\t\tvar w = Math.max(1, Math.round(this.bounds.width));
\t\tvar h = Math.max(1, Math.round(this.bounds.height));
\t\tnode.coordsize = (w * this.vmlScale) + ',' + (h * this.vmlScale);
\t\tcanvas.scale(this.vmlScale);
\t\tcanvas.vmlScale = this.vmlScale;
\t}

\t// Painting relative to top, left shape corner
\tvar s = this.scale;
\tcanvas.translate(-Math.round(this.bounds.x / s), -Math.round(this.bounds.y / s));
\t
\treturn canvas;
};

/**
 * Function: updateVmlContainer
 * 
 * Updates the bounds of the VML container.
 */
mxShape.prototype.updateVmlContainer = function()
{
\tthis.node.style.left = Math.round(this.bounds.x) + 'px';
\tthis.node.style.top = Math.round(this.bounds.y) + 'px';
\tvar w = Math.max(1, Math.round(this.bounds.width));
\tvar h = Math.max(1, Math.round(this.bounds.height));
\tthis.node.style.width = w + 'px';
\tthis.node.style.height = h + 'px';
\tthis.node.style.overflow = 'visible';
};

/**
 * Function: redrawHtml
 *
 * Allow optimization by replacing VML with HTML.
 */
mxShape.prototype.redrawHtmlShape = function()
{
\t// LATER: Refactor methods
\tthis.updateHtmlBounds(this.node);
\tthis.updateHtmlFilters(this.node);
\tthis.updateHtmlColors(this.node);
};

/**
 * Function: updateHtmlFilters
 *
 * Allow optimization by replacing VML with HTML.
 */
mxShape.prototype.updateHtmlFilters = function(node)
{
\tvar f = '';
\t
\tif (this.opacity < 100)
\t{
\t\tf += 'alpha(opacity=' + (this.opacity) + ')';
\t}
\t
\tif (this.isShadow)
\t{
\t\t// FIXME: Cannot implement shadow transparency with filter
\t\tf += 'progid:DXImageTransform.Microsoft.dropShadow (' +
\t\t\t'OffX=\\'' + Math.round(mxConstants.SHADOW_OFFSET_X * this.scale) + '\\', ' +
\t\t\t'OffY=\\'' + Math.round(mxConstants.SHADOW_OFFSET_Y * this.scale) + '\\', ' +
\t\t\t'Color=\\'' + mxConstants.VML_SHADOWCOLOR + '\\')';
\t}
\t
\tif (this.fill != null && this.fill != mxConstants.NONE && this.gradient && this.gradient != mxConstants.NONE)
\t{
\t\tvar start = this.fill;
\t\tvar end = this.gradient;
\t\tvar type = '0';
\t\t
\t\tvar lookup = {east:0,south:1,west:2,north:3};
\t\tvar dir = (this.direction != null) ? lookup[this.direction] : 0;
\t\t
\t\tif (this.gradientDirection != null)
\t\t{
\t\t\tdir = mxUtils.mod(dir + lookup[this.gradientDirection] - 1, 4);
\t\t}

\t\tif (dir == 1)
\t\t{
\t\t\ttype = '1';
\t\t\tvar tmp = start;
\t\t\tstart = end;
\t\t\tend = tmp;
\t\t}
\t\telse if (dir == 2)
\t\t{
\t\t\tvar tmp = start;
\t\t\tstart = end;
\t\t\tend = tmp;
\t\t}
\t\telse if (dir == 3)
\t\t{
\t\t\ttype = '1';
\t\t}
\t\t
\t\tf += 'progid:DXImageTransform.Microsoft.gradient(' +
\t\t\t'startColorStr=\\'' + start + '\\', endColorStr=\\'' + end +
\t\t\t'\\', gradientType=\\'' + type + '\\')';
\t}

\tnode.style.filter = f;
};

/**
 * Function: updateHtmlColors
 *
 * Allow optimization by replacing VML with HTML.
 */
mxShape.prototype.updateHtmlColors = function(node)
{
\tvar color = this.stroke;
\t
\tif (color != null && color != mxConstants.NONE)
\t{
\t\tnode.style.borderColor = color;

\t\tif (this.isDashed)
\t\t{
\t\t\tnode.style.borderStyle = 'dashed';
\t\t}
\t\telse if (this.strokewidth > 0)
\t\t{
\t\t\tnode.style.borderStyle = 'solid';
\t\t}

\t\tnode.style.borderWidth = Math.max(1, Math.ceil(this.strokewidth * this.scale)) + 'px';
\t}
\telse
\t{
\t\tnode.style.borderWidth = '0px';
\t}

\tcolor = (this.outline) ? null : this.fill;
\t
\tif (color != null && color != mxConstants.NONE)
\t{
\t\tnode.style.backgroundColor = color;
\t\tnode.style.backgroundImage = 'none';
\t}
\telse if (this.pointerEvents)
\t{
\t\t node.style.backgroundColor = 'transparent';
\t}
\telse if (document.documentMode == 8)
\t{
\t\tmxUtils.addTransparentBackgroundFilter(node);
\t}
\telse
\t{
\t\tthis.setTransparentBackgroundImage(node);
\t}
};

/**
 * Function: updateHtmlBounds
 *
 * Allow optimization by replacing VML with HTML.
 */
mxShape.prototype.updateHtmlBounds = function(node)
{
\tvar sw = (document.documentMode >= 9) ? 0 : Math.ceil(this.strokewidth * this.scale);
\tnode.style.borderWidth = Math.max(1, sw) + 'px';
\tnode.style.overflow = 'hidden';
\t
\tnode.style.left = Math.round(this.bounds.x - sw / 2) + 'px';
\tnode.style.top = Math.round(this.bounds.y - sw / 2) + 'px';

\tif (document.compatMode == 'CSS1Compat')
\t{
\t\tsw = -sw;
\t}
\t
\tnode.style.width = Math.round(Math.max(0, this.bounds.width + sw)) + 'px';
\tnode.style.height = Math.round(Math.max(0, this.bounds.height + sw)) + 'px';
};

/**
 * Function: destroyCanvas
 * 
 * Destroys the given canvas which was used for drawing. This implementation
 * increments the reference counts on all shared gradients used in the canvas.
 */
mxShape.prototype.destroyCanvas = function(canvas)
{
\t// Manages reference counts
\tif (canvas instanceof mxSvgCanvas2D)
\t{
\t\t// Increments ref counts
\t\tfor (var key in canvas.gradients)
\t\t{
\t\t\tvar gradient = canvas.gradients[key];
\t\t\t
\t\t\tif (gradient != null)
\t\t\t{
\t\t\t\tgradient.mxRefCount = (gradient.mxRefCount || 0) + 1;
\t\t\t}
\t\t}
\t\t
\t\tthis.releaseSvgGradients(this.oldGradients);
\t\tthis.oldGradients = canvas.gradients;
\t}
};

/**
 * Function: beforePaint
 * 
 * Invoked before paint is called.
 */
mxShape.prototype.beforePaint = function(c) { }

/**
 * Function: afterPaint
 * 
 * Invokes after paint was called.
 */
mxShape.prototype.afterPaint = function(c) { }

/**
 * Function: paint
 * 
 * Generic rendering code.
 */
mxShape.prototype.paint = function(c)
{
\tvar strokeDrawn = false;
\t
\tif (c != null && this.outline)
\t{
\t\tvar stroke = c.stroke;
\t\t
\t\tc.stroke = function()
\t\t{
\t\t\tstrokeDrawn = true;
\t\t\tstroke.apply(this, arguments);
\t\t};

\t\tvar fillAndStroke = c.fillAndStroke;
\t\t
\t\tc.fillAndStroke = function()
\t\t{
\t\t\tstrokeDrawn = true;
\t\t\tfillAndStroke.apply(this, arguments);
\t\t};
\t}

\t// Scale is passed-through to canvas
\tvar s = this.scale;
\tvar x = this.bounds.x / s;
\tvar y = this.bounds.y / s;
\tvar w = this.bounds.width / s;
\tvar h = this.bounds.height / s;

\tif (this.isPaintBoundsInverted())
\t{
\t\tvar t = (w - h) / 2;
\t\tx += t;
\t\ty -= t;
\t\tvar tmp = w;
\t\tw = h;
\t\th = tmp;
\t}
\t
\tthis.updateTransform(c, x, y, w, h);
\tthis.configureCanvas(c, x, y, w, h);

\t// Adds background rectangle to capture events
\tvar bg = null;
\t
\tif ((this.stencil == null && this.points == null && this.shapePointerEvents) ||
\t\t(this.stencil != null && this.stencilPointerEvents))
\t{
\t\tvar bb = this.createBoundingBox();
\t\t
\t\tif (this.dialect == mxConstants.DIALECT_SVG)
\t\t{
\t\t\tbg = this.createTransparentSvgRectangle(bb.x, bb.y, bb.width, bb.height);
\t\t\tthis.node.appendChild(bg);
\t\t}
\t\telse
\t\t{
\t\t\tvar rect = c.createRect('rect', bb.x / s, bb.y / s, bb.width / s, bb.height / s);
\t\t\trect.appendChild(c.createTransparentFill());
\t\t\trect.stroked = 'false';
\t\t\tc.root.appendChild(rect);
\t\t}
\t}

\tif (this.stencil != null)
\t{
\t\tthis.stencil.drawShape(c, this, x, y, w, h);
\t}
\telse
\t{
\t\t// Stencils have separate strokewidth
\t\tc.setStrokeWidth(this.strokewidth);
\t\t
\t\tif (this.points != null)
\t\t{
\t\t\t// Paints edge shape
\t\t\tvar pts = [];
\t\t\t
\t\t\tfor (var i = 0; i < this.points.length; i++)
\t\t\t{
\t\t\t\tif (this.points[i] != null)
\t\t\t\t{
\t\t\t\t\tpts.push(new mxPoint(this.points[i].x / s, this.points[i].y / s));
\t\t\t\t}
\t\t\t}

\t\t\tthis.paintEdgeShape(c, pts);
\t\t}
\t\telse
\t\t{
\t\t\t// Paints vertex shape
\t\t\tthis.paintVertexShape(c, x, y, w, h);
\t\t}
\t}
\t
\tif (bg != null && c.state != null && c.state.transform != null)
\t{
\t\tbg.setAttribute('transform', c.state.transform);
\t}
\t
\t// Draws highlight rectangle if no stroke was used
\tif (c != null && this.outline && !strokeDrawn)
\t{
\t\tc.rect(x, y, w, h);
\t\tc.stroke();
\t}
};

/**
 * Function: configureCanvas
 * 
 * Sets the state of the canvas for drawing the shape.
 */
mxShape.prototype.configureCanvas = function(c, x, y, w, h)
{
\tvar dash = null;
\t
\tif (this.style != null)
\t{
\t\tdash = this.style['dashPattern'];\t\t
\t}

\tc.setAlpha(this.opacity / 100);
\tc.setFillAlpha(this.fillOpacity / 100);
\tc.setStrokeAlpha(this.strokeOpacity / 100);

\t// Sets alpha, colors and gradients
\tif (this.isShadow != null)
\t{
\t\tc.setShadow(this.isShadow);
\t}
\t
\t// Dash pattern
\tif (this.isDashed != null)
\t{
\t\tc.setDashed(this.isDashed, (this.style != null) ?
\t\t\tmxUtils.getValue(this.style, mxConstants.STYLE_FIX_DASH, false) == 1 : false);
\t}

\tif (dash != null)
\t{
\t\tc.setDashPattern(dash);
\t}

\tif (this.fill != null && this.fill != mxConstants.NONE && this.gradient && this.gradient != mxConstants.NONE)
\t{
\t\tvar b = this.getGradientBounds(c, x, y, w, h);
\t\tc.setGradient(this.fill, this.gradient, b.x, b.y, b.width, b.height, this.gradientDirection);
\t}
\telse
\t{
\t\tc.setFillColor(this.fill);
\t}

\tc.setStrokeColor(this.stroke);
};

/**
 * Function: getGradientBounds
 * 
 * Returns the bounding box for the gradient box for this shape.
 */
mxShape.prototype.getGradientBounds = function(c, x, y, w, h)
{
\treturn new mxRectangle(x, y, w, h);
};

/**
 * Function: updateTransform
 * 
 * Sets the scale and rotation on the given canvas.
 */
mxShape.prototype.updateTransform = function(c, x, y, w, h)
{
\t// NOTE: Currently, scale is implemented in state and canvas. This will
\t// move to canvas in a later version, so that the states are unscaled
\t// and untranslated and do not need an update after zooming or panning.
\tc.scale(this.scale);
\tc.rotate(this.getShapeRotation(), this.flipH, this.flipV, x + w / 2, y + h / 2);
};

/**
 * Function: paintVertexShape
 * 
 * Paints the vertex shape.
 */
mxShape.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tthis.paintBackground(c, x, y, w, h);
\t
\tif (!this.outline || this.style == null || mxUtils.getValue(
\t\tthis.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0)
\t{
\t\tc.setShadow(false);
\t\tthis.paintForeground(c, x, y, w, h);
\t}
};

/**
 * Function: paintBackground
 * 
 * Hook for subclassers. This implementation is empty.
 */
mxShape.prototype.paintBackground = function(c, x, y, w, h) { };

/**
 * Function: paintForeground
 * 
 * Hook for subclassers. This implementation is empty.
 */
mxShape.prototype.paintForeground = function(c, x, y, w, h) { };

/**
 * Function: paintEdgeShape
 * 
 * Hook for subclassers. This implementation is empty.
 */
mxShape.prototype.paintEdgeShape = function(c, pts) { };

/**
 * Function: getArcSize
 * 
 * Returns the arc size for the given dimension.
 */
mxShape.prototype.getArcSize = function(w, h)
{
\tvar r = 0;
\t
\tif (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
\t{
\t\tr = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
\t\t\tmxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
\t}
\telse
\t{
\t\tvar f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
\t\t\tmxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
\t\tr = Math.min(w * f, h * f);
\t}
\t
\treturn r;
};

/**
 * Function: paintGlassEffect
 * 
 * Paints the glass gradient effect.
 */
mxShape.prototype.paintGlassEffect = function(c, x, y, w, h, arc)
{
\tvar sw = Math.ceil(this.strokewidth / 2);
\tvar size = 0.4;
\t
\tc.setGradient('#ffffff', '#ffffff', x, y, w, h * 0.6, 'south', 0.9, 0.1);
\tc.begin();
\tarc += 2 * sw;
\t\t
\tif (this.isRounded)
\t{
\t\tc.moveTo(x - sw + arc, y - sw);
\t\tc.quadTo(x - sw, y - sw, x - sw, y - sw + arc);
\t\tc.lineTo(x - sw, y + h * size);
\t\tc.quadTo(x + w * 0.5, y + h * 0.7, x + w + sw, y + h * size);
\t\tc.lineTo(x + w + sw, y - sw + arc);
\t\tc.quadTo(x + w + sw, y - sw, x + w + sw - arc, y - sw);
\t}
\telse
\t{
\t\tc.moveTo(x - sw, y - sw);
\t\tc.lineTo(x - sw, y + h * size);
\t\tc.quadTo(x + w * 0.5, y + h * 0.7, x + w + sw, y + h * size);
\t\tc.lineTo(x + w + sw, y - sw);
\t}
\t
\tc.close();
\tc.fill();
};

/**
 * Function: addPoints
 * 
 * Paints the given points with rounded corners.
 */
mxShape.prototype.addPoints = function(c, pts, rounded, arcSize, close, exclude, initialMove)
{
\tif (pts != null && pts.length > 0)
\t{
\t\tinitialMove = (initialMove != null) ? initialMove : true;
\t\tvar pe = pts[pts.length - 1];
\t\t
\t\t// Adds virtual waypoint in the center between start and end point
\t\tif (close && rounded)
\t\t{
\t\t\tpts = pts.slice();
\t\t\tvar p0 = pts[0];
\t\t\tvar wp = new mxPoint(pe.x + (p0.x - pe.x) / 2, pe.y + (p0.y - pe.y) / 2);
\t\t\tpts.splice(0, 0, wp);
\t\t}
\t
\t\tvar pt = pts[0];
\t\tvar i = 1;
\t
\t\t// Draws the line segments
\t\tif (initialMove)
\t\t{
\t\t\tc.moveTo(pt.x, pt.y);
\t\t}
\t\telse
\t\t{
\t\t\tc.lineTo(pt.x, pt.y);
\t\t}
\t\t
\t\twhile (i < ((close) ? pts.length : pts.length - 1))
\t\t{
\t\t\tvar tmp = pts[mxUtils.mod(i, pts.length)];
\t\t\tvar dx = pt.x - tmp.x;
\t\t\tvar dy = pt.y - tmp.y;
\t
\t\t\tif (rounded && (dx != 0 || dy != 0) && (exclude == null || mxUtils.indexOf(exclude, i - 1) < 0))
\t\t\t{
\t\t\t\t// Draws a line from the last point to the current
\t\t\t\t// point with a spacing of size off the current point
\t\t\t\t// into direction of the last point
\t\t\t\tvar dist = Math.sqrt(dx * dx + dy * dy);
\t\t\t\tvar nx1 = dx * Math.min(arcSize, dist / 2) / dist;
\t\t\t\tvar ny1 = dy * Math.min(arcSize, dist / 2) / dist;
\t
\t\t\t\tvar x1 = tmp.x + nx1;
\t\t\t\tvar y1 = tmp.y + ny1;
\t\t\t\tc.lineTo(x1, y1);
\t
\t\t\t\t// Draws a curve from the last point to the current
\t\t\t\t// point with a spacing of size off the current point
\t\t\t\t// into direction of the next point
\t\t\t\tvar next = pts[mxUtils.mod(i + 1, pts.length)];
\t\t\t\t
\t\t\t\t// Uses next non-overlapping point
\t\t\t\twhile (i < pts.length - 2 && Math.round(next.x - tmp.x) == 0 && Math.round(next.y - tmp.y) == 0)
\t\t\t\t{
\t\t\t\t\tnext = pts[mxUtils.mod(i + 2, pts.length)];
\t\t\t\t\ti++;
\t\t\t\t}
\t\t\t\t
\t\t\t\tdx = next.x - tmp.x;
\t\t\t\tdy = next.y - tmp.y;
\t
\t\t\t\tdist = Math.max(1, Math.sqrt(dx * dx + dy * dy));
\t\t\t\tvar nx2 = dx * Math.min(arcSize, dist / 2) / dist;
\t\t\t\tvar ny2 = dy * Math.min(arcSize, dist / 2) / dist;
\t
\t\t\t\tvar x2 = tmp.x + nx2;
\t\t\t\tvar y2 = tmp.y + ny2;
\t
\t\t\t\tc.quadTo(tmp.x, tmp.y, x2, y2);
\t\t\t\ttmp = new mxPoint(x2, y2);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tc.lineTo(tmp.x, tmp.y);
\t\t\t}
\t
\t\t\tpt = tmp;
\t\t\ti++;
\t\t}
\t
\t\tif (close)
\t\t{
\t\t\tc.close();
\t\t}
\t\telse
\t\t{
\t\t\tc.lineTo(pe.x, pe.y);
\t\t}
\t}
};

/**
 * Function: resetStyles
 * 
 * Resets all styles.
 */
mxShape.prototype.resetStyles = function()
{
\tthis.initStyles();

\tthis.spacing = 0;
\t
\tdelete this.fill;
\tdelete this.gradient;
\tdelete this.gradientDirection;
\tdelete this.stroke;
\tdelete this.startSize;
\tdelete this.endSize;
\tdelete this.startArrow;
\tdelete this.endArrow;
\tdelete this.direction;
\tdelete this.isShadow;
\tdelete this.isDashed;
\tdelete this.isRounded;
\tdelete this.glass;
};

/**
 * Function: apply
 * 
 * Applies the style of the given <mxCellState> to the shape. This
 * implementation assigns the following styles to local fields:
 * 
 * - <mxConstants.STYLE_FILLCOLOR> => fill
 * - <mxConstants.STYLE_GRADIENTCOLOR> => gradient
 * - <mxConstants.STYLE_GRADIENT_DIRECTION> => gradientDirection
 * - <mxConstants.STYLE_OPACITY> => opacity
 * - <mxConstants.STYLE_FILL_OPACITY> => fillOpacity
 * - <mxConstants.STYLE_STROKE_OPACITY> => strokeOpacity
 * - <mxConstants.STYLE_STROKECOLOR> => stroke
 * - <mxConstants.STYLE_STROKEWIDTH> => strokewidth
 * - <mxConstants.STYLE_SHADOW> => isShadow
 * - <mxConstants.STYLE_DASHED> => isDashed
 * - <mxConstants.STYLE_SPACING> => spacing
 * - <mxConstants.STYLE_STARTSIZE> => startSize
 * - <mxConstants.STYLE_ENDSIZE> => endSize
 * - <mxConstants.STYLE_ROUNDED> => isRounded
 * - <mxConstants.STYLE_STARTARROW> => startArrow
 * - <mxConstants.STYLE_ENDARROW> => endArrow
 * - <mxConstants.STYLE_ROTATION> => rotation
 * - <mxConstants.STYLE_DIRECTION> => direction
 * - <mxConstants.STYLE_GLASS> => glass
 *
 * This keeps a reference to the <style>. If you need to keep a reference to
 * the cell, you can override this method and store a local reference to
 * state.cell or the <mxCellState> itself. If <outline> should be true, make
 * sure to set it before calling this method.
 *
 * Parameters:
 *
 * state - <mxCellState> of the corresponding cell.
 */
mxShape.prototype.apply = function(state)
{
\tthis.state = state;
\tthis.style = state.style;

\tif (this.style != null)
\t{
\t\tthis.fill = mxUtils.getValue(this.style, mxConstants.STYLE_FILLCOLOR, this.fill);
\t\tthis.gradient = mxUtils.getValue(this.style, mxConstants.STYLE_GRADIENTCOLOR, this.gradient);
\t\tthis.gradientDirection = mxUtils.getValue(this.style, mxConstants.STYLE_GRADIENT_DIRECTION, this.gradientDirection);
\t\tthis.opacity = mxUtils.getValue(this.style, mxConstants.STYLE_OPACITY, this.opacity);
\t\tthis.fillOpacity = mxUtils.getValue(this.style, mxConstants.STYLE_FILL_OPACITY, this.fillOpacity);
\t\tthis.strokeOpacity = mxUtils.getValue(this.style, mxConstants.STYLE_STROKE_OPACITY, this.strokeOpacity);
\t\tthis.stroke = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, this.stroke);
\t\tthis.strokewidth = mxUtils.getNumber(this.style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth);
\t\tthis.spacing = mxUtils.getValue(this.style, mxConstants.STYLE_SPACING, this.spacing);
\t\tthis.startSize = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, this.startSize);
\t\tthis.endSize = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, this.endSize);
\t\tthis.startArrow = mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, this.startArrow);
\t\tthis.endArrow = mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, this.endArrow);
\t\tthis.rotation = mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, this.rotation);
\t\tthis.direction = mxUtils.getValue(this.style, mxConstants.STYLE_DIRECTION, this.direction);
\t\tthis.flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, 0) == 1;
\t\tthis.flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, 0) == 1;\t
\t\t
\t\t// Legacy support for stencilFlipH/V
\t\tif (this.stencil != null)
\t\t{
\t\t\tthis.flipH = mxUtils.getValue(this.style, 'stencilFlipH', 0) == 1 || this.flipH;
\t\t\tthis.flipV = mxUtils.getValue(this.style, 'stencilFlipV', 0) == 1 || this.flipV;
\t\t}
\t\t
\t\tif (this.direction == mxConstants.DIRECTION_NORTH || this.direction == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\tvar tmp = this.flipH;
\t\t\tthis.flipH = this.flipV;
\t\t\tthis.flipV = tmp;
\t\t}

\t\tthis.isShadow = mxUtils.getValue(this.style, mxConstants.STYLE_SHADOW, this.isShadow) == 1;
\t\tthis.isDashed = mxUtils.getValue(this.style, mxConstants.STYLE_DASHED, this.isDashed) == 1;
\t\tthis.isRounded = mxUtils.getValue(this.style, mxConstants.STYLE_ROUNDED, this.isRounded) == 1;
\t\tthis.glass = mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, this.glass) == 1;
\t\t
\t\tif (this.fill == mxConstants.NONE)
\t\t{
\t\t\tthis.fill = null;
\t\t}

\t\tif (this.gradient == mxConstants.NONE)
\t\t{
\t\t\tthis.gradient = null;
\t\t}

\t\tif (this.stroke == mxConstants.NONE)
\t\t{
\t\t\tthis.stroke = null;
\t\t}
\t}
};

/**
 * Function: setCursor
 * 
 * Sets the cursor on the given shape.
 *
 * Parameters:
 *
 * cursor - The cursor to be used.
 */
mxShape.prototype.setCursor = function(cursor)
{
\tif (cursor == null)
\t{
\t\tcursor = '';
\t}
\t
\tthis.cursor = cursor;

\tif (this.node != null)
\t{
\t\tthis.node.style.cursor = cursor;
\t}
};

/**
 * Function: getCursor
 * 
 * Returns the current cursor.
 */
mxShape.prototype.getCursor = function()
{
\treturn this.cursor;
};

/**
 * Function: isRoundable
 * 
 * Hook for subclassers.
 */
mxShape.prototype.isRoundable = function()
{
\treturn false;
};

/**
 * Function: updateBoundingBox
 *
 * Updates the <boundingBox> for this shape using <createBoundingBox> and
 * <augmentBoundingBox> and stores the result in <boundingBox>.
 */
mxShape.prototype.updateBoundingBox = function()
{
\t// Tries to get bounding box from SVG subsystem
\t// LATER: Use getBoundingClientRect for fallback in VML
\tif (this.useSvgBoundingBox && this.node != null && this.node.ownerSVGElement != null)
\t{
\t\ttry
\t\t{
\t\t\tvar b = this.node.getBBox();
\t
\t\t\tif (b.width > 0 && b.height > 0)
\t\t\t{
\t\t\t\tthis.boundingBox = new mxRectangle(b.x, b.y, b.width, b.height);
\t\t\t\t
\t\t\t\t// Adds strokeWidth
\t\t\t\tthis.boundingBox.grow(this.strokewidth * this.scale / 2);
\t\t\t\t
\t\t\t\treturn;
\t\t\t}
\t\t}
\t\tcatch(e)
\t\t{
\t\t\t// fallback to code below
\t\t}
\t}

\tif (this.bounds != null)
\t{
\t\tvar bbox = this.createBoundingBox();
\t\t
\t\tif (bbox != null)
\t\t{
\t\t\tthis.augmentBoundingBox(bbox);
\t\t\tvar rot = this.getShapeRotation();
\t\t\t
\t\t\tif (rot != 0)
\t\t\t{
\t\t\t\tbbox = mxUtils.getBoundingBox(bbox, rot);
\t\t\t}
\t\t}

\t\tthis.boundingBox = bbox;
\t}
};

/**
 * Function: createBoundingBox
 *
 * Returns a new rectangle that represents the bounding box of the bare shape
 * with no shadows or strokewidths.
 */
mxShape.prototype.createBoundingBox = function()
{
\tvar bb = this.bounds.clone();

\tif ((this.stencil != null && (this.direction == mxConstants.DIRECTION_NORTH ||
\t\tthis.direction == mxConstants.DIRECTION_SOUTH)) || this.isPaintBoundsInverted())
\t{
\t\tbb.rotate90();
\t}
\t
\treturn bb;
};

/**
 * Function: augmentBoundingBox
 *
 * Augments the bounding box with the strokewidth and shadow offsets.
 */
mxShape.prototype.augmentBoundingBox = function(bbox)
{
\tif (this.isShadow)
\t{
\t\tbbox.width += Math.ceil(mxConstants.SHADOW_OFFSET_X * this.scale);
\t\tbbox.height += Math.ceil(mxConstants.SHADOW_OFFSET_Y * this.scale);
\t}
\t
\t// Adds strokeWidth
\tbbox.grow(this.strokewidth * this.scale / 2);
};

/**
 * Function: isPaintBoundsInverted
 * 
 * Returns true if the bounds should be inverted.
 */
mxShape.prototype.isPaintBoundsInverted = function()
{
\t// Stencil implements inversion via aspect
\treturn this.stencil == null && (this.direction == mxConstants.DIRECTION_NORTH ||
\t\t\tthis.direction == mxConstants.DIRECTION_SOUTH);
};

/**
 * Function: getRotation
 * 
 * Returns the rotation from the style.
 */
mxShape.prototype.getRotation = function()
{
\treturn (this.rotation != null) ? this.rotation : 0;
};

/**
 * Function: getTextRotation
 * 
 * Returns the rotation for the text label.
 */
mxShape.prototype.getTextRotation = function()
{
\tvar rot = this.getRotation();
\t
\tif (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, 1) != 1)
\t{
\t\trot += mxText.prototype.verticalTextRotation;
\t}
\t
\treturn rot;
};

/**
 * Function: getShapeRotation
 * 
 * Returns the actual rotation of the shape.
 */
mxShape.prototype.getShapeRotation = function()
{
\tvar rot = this.getRotation();
\t
\tif (this.direction != null)
\t{
\t\tif (this.direction == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\trot += 270;
\t\t}
\t\telse if (this.direction == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\trot += 180;
\t\t}
\t\telse if (this.direction == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\trot += 90;
\t\t}
\t}
\t
\treturn rot;
};

/**
 * Function: createTransparentSvgRectangle
 * 
 * Adds a transparent rectangle that catches all events.
 */
mxShape.prototype.createTransparentSvgRectangle = function(x, y, w, h)
{
\tvar rect = document.createElementNS(mxConstants.NS_SVG, 'rect');
\trect.setAttribute('x', x);
\trect.setAttribute('y', y);
\trect.setAttribute('width', w);
\trect.setAttribute('height', h);
\trect.setAttribute('fill', 'none');
\trect.setAttribute('stroke', 'none');
\trect.setAttribute('pointer-events', 'all');
\t
\treturn rect;
};

/**
 * Function: setTransparentBackgroundImage
 * 
 * Sets a transparent background CSS style to catch all events.
 * 
 * Paints the line shape.
 */
mxShape.prototype.setTransparentBackgroundImage = function(node)
{
\tnode.style.backgroundImage = 'url(\\'' + mxClient.imageBasePath + '/transparent.gif\\')';
};

/**
 * Function: releaseSvgGradients
 * 
 * Paints the line shape.
 */
mxShape.prototype.releaseSvgGradients = function(grads)
{
\tif (grads != null)
\t{
\t\tfor (var key in grads)
\t\t{
\t\t\tvar gradient = grads[key];
\t\t\t
\t\t\tif (gradient != null)
\t\t\t{
\t\t\t\tgradient.mxRefCount = (gradient.mxRefCount || 0) - 1;
\t\t\t\t
\t\t\t\tif (gradient.mxRefCount == 0 && gradient.parentNode != null)
\t\t\t\t{
\t\t\t\t\tgradient.parentNode.removeChild(gradient);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: destroy
 *
 * Destroys the shape by removing it from the DOM and releasing the DOM
 * node associated with the shape using <mxEvent.release>.
 */
mxShape.prototype.destroy = function()
{
\tif (this.node != null)
\t{
\t\tmxEvent.release(this.node);
\t\t
\t\tif (this.node.parentNode != null)
\t\t{
\t\t\tthis.node.parentNode.removeChild(this.node);
\t\t}
\t\t
\t\tthis.node = null;
\t}
\t
\t// Decrements refCount and removes unused
\tthis.releaseSvgGradients(this.oldGradients);
\tthis.oldGradients = null;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStencil
 *
 * Implements a generic shape which is based on a XML node as a description.
 * 
 * shape:
 * 
 * The outer element is *shape*, that has attributes:
 * 
 * - \"name\", string, required. The stencil name that uniquely identifies the shape.
 * - \"w\" and \"h\" are optional decimal view bounds. This defines your co-ordinate
 * system for the graphics operations in the shape. The default is 100,100.
 * - \"aspect\", optional string. Either \"variable\", the default, or \"fixed\". Fixed
 * means always render the shape with the aspect ratio defined by the ratio w/h.
 * Variable causes the ratio to match that of the geometry of the current vertex.
 * - \"strokewidth\", optional string. Either an integer or the string \"inherit\".
 * \"inherit\" indicates that the strokeWidth of the cell is only changed on scaling,
 * not on resizing. Default is \"1\".
 * If numeric values are used, the strokeWidth of the cell is changed on both
 * scaling and resizing and the value defines the multiple that is applied to
 * the width.
 * 
 * connections:
 * 
 * If you want to define specific fixed connection points on the shape use the
 * *connections* element. Each *constraint* element within connections defines
 * a fixed connection point on the shape. Constraints have attributes:
 * 
 * - \"perimeter\", required. 1 or 0. 0 sets the connection point where specified
 * by x,y. 1 Causes the position of the connection point to be extrapolated from
 * the center of the shape, through x,y to the point of intersection with the
 * perimeter of the shape.
 * - \"x\" and \"y\" are the position of the fixed point relative to the bounds of
 * the shape. They can be automatically adjusted if perimeter=1. So, (0,0) is top
 * left, (0.5,0.5) the center, (1,0.5) the center of the right hand edge of the
 * bounds, etc. Values may be less than 0 or greater than 1 to be positioned
 * outside of the shape.
 * - \"name\", optional string. A unique identifier for the port on the shape.
 * 
 * background and foreground:
 * 
 * The path of the graphics drawing is split into two elements, *foreground* and
 * *background*. The split is to define which part any shadow applied to the shape
 * is derived from (the background). This, generally, means the background is the
 * line tracing of the outside of the shape, but not always.
 * 
 * Any stroke, fill or fillstroke of a background must be the first element of the
 * foreground element, they must not be used within *background*. If the background
 * is empty, this is not required.
 * 
 * Because the background cannot have any fill or stroke, it can contain only one
 * *path*, *rect*, *roundrect* or *ellipse* element (or none). It can also not
 * include *image*, *text* or *include-shape*.
 * 
 * Note that the state, styling and drawing in mxGraph stencils is very close in
 * design to that of HTML 5 canvas. Tutorials on this subject, if you're not
 * familiar with the topic, will give a good high-level introduction to the
 * concepts used.
 * 
 * State:
 * 
 * Rendering within the foreground and background elements has the concept of
 * state. There are two types of operations other than state save/load, styling
 * and drawing. The styling operations change the current state, so you can save
 * the current state with <save/> and pull the last saved state from the state
 * stack using <restore/>.
 * 
 * Styling:
 * 
 * The elements that change colors within the current state all take a hash
 * prefixed hex color code (\"#FFEA80\").
 * 
 * - *strokecolor*, this sets the color that drawing paths will be rendered in
 * when a stroke or fillstroke command is issued.
 * - *fillcolor*, this sets the color that the inside of closed paths will be
 * rendered in when a fill or fillstroke command is issued.
 * - *fontcolor*, this sets the color that fonts are rendered in when text is drawn.
 * 
 * *alpha* defines the degree of transparency used between 1.0 for fully opaque
 * and 0.0 for fully transparent.
 * 
 * *fillalpha* defines the degree of fill transparency used between 1.0 for fully
 * opaque and 0.0 for fully transparent.
 * 
 * *strokealpha* defines the degree of stroke transparency used between 1.0 for
 * fully opaque and 0.0 for fully transparent.
 * 
 * *strokewidth* defines the integer thickness of drawing elements rendered by
 * stroking. Use fixed=\"1\" to apply the value as-is, without scaling.
 * 
 * *dashed* is \"1\" for dashing enabled and \"0\" for disabled.
 * 
 * When *dashed* is enabled the current dash pattern, defined by *dashpattern*,
 * is used on strokes. dashpattern is a sequence of space separated \"on, off\"
 * lengths that define what distance to paint the stroke for, then what distance
 * to paint nothing for, repeat... The default is \"3 3\". You could define a more
 * complex pattern with \"5 3 2 6\", for example. Generally, it makes sense to have
 * an even number of elements in the dashpattern, but that's not required.
 * 
 * *linejoin*, *linecap* and *miterlimit* are best explained by the Mozilla page
 * on Canvas styling (about halfway down). The values are all the same except we
 * use \"flat\" for linecap, instead of Canvas' \"butt\".
 * 
 * For font styling there are.
 * 
 * - *fontsize*, an integer,
 * - *fontstyle*, an ORed bit pattern of bold (1), italic (2) and underline (4),
 * i.e bold underline is \"5\".
 * - *fontfamily*, is a string defining the typeface to be used.
 * 
 * Drawing:
 * 
 * Most drawing is contained within a *path* element. Again, the graphic
 * primitives are very similar to that of HTML 5 canvas.
 * 
 * - *move* to attributes required decimals (x,y).
 * - *line* to attributes required decimals (x,y).
 * - *quad* to required decimals (x2,y2) via control point required decimals
 * (x1,y1).
 * - *curve* to required decimals (x3,y3), via control points required decimals
 * (x1,y1) and (x2,y2).
 * - *arc*, this doesn't follow the HTML Canvas signatures, instead it's a copy
 * of the SVG arc command. The SVG specification documentation gives the best
 * description of its behaviors. The attributes are named identically, they are
 * decimals and all required.
 * - *close* ends the current subpath and causes an automatic straight line to
 * be drawn from the current point to the initial point of the current subpath.
 * 
 * Complex drawing:
 * 
 * In addition to the graphics primitive operations there are non-primitive
 * operations. These provide an easy method to draw some basic shapes.
 * 
 * - *rect*, attributes \"x\", \"y\", \"w\", \"h\", all required decimals
 * - *roundrect*, attributes \"x\", \"y\", \"w\", \"h\", all required decimals. Also
 * \"arcsize\" an optional decimal attribute defining how large, the corner curves
 * are.
 * - *ellipse*, attributes \"x\", \"y\", \"w\", \"h\", all required decimals.
 * 
 * Note that these 3 shapes and all paths must be followed by either a fill,
 * stroke, or fillstroke.
 * 
 * Text:
 * 
 * *text* elements have the following attributes.
 * 
 * - \"str\", the text string to display, required.
 * - \"x\" and \"y\", the decimal location (x,y) of the text element, required.
 * - \"align\", the horizontal alignment of the text element, either \"left\",
 * \"center\" or \"right\". Optional, default is \"left\".
 * - \"valign\", the vertical alignment of the text element, either \"top\", \"middle\"
 * or \"bottom\". Optional, default is \"top\".
 * - \"localized\", 0 or 1, if 1 then the \"str\" actually contains a key to use to
 * fetch the value out of mxResources. Optional, default is
 * <mxStencil.defaultLocalized>.
 * - \"vertical\", 0 or 1, if 1 the label is rendered vertically (rotated by 90
 * degrees). Optional, default is 0.
 * - \"rotation\", angle in degrees (0 to 360). The angle to rotate the text by.
 * Optional, default is 0.
 * - \"align-shape\", 0 or 1, if 0 ignore the rotation of the shape when setting
 * the text rotation. Optional, default is 1.
 * 
 * If <allowEval> is true, then the text content of the this element can define
 * a function which is invoked with the shape as the only argument and returns
 * the value for the text element (ignored if the str attribute is not null).
 * 
 * Images:
 * 
 * *image* elements can either be external URLs, or data URIs, where supported
 * (not in IE 7-). Attributes are:
 * 
 * - \"src\", required string. Either a data URI or URL.
 * - \"x\", \"y\", required decimals. The (x,y) position of the image.
 * - \"w\", \"h\", required decimals. The width and height of the image.
 * - \"flipH\" and \"flipV\", optional 0 or 1. Whether to flip the image along the
 * horizontal/vertical axis. Default is 0 for both.
 * 
 * If <allowEval> is true, then the text content of the this element can define
 * a function which is invoked with the shape as the only argument and returns
 * the value for the image source (ignored if the src attribute is not null).
 * 
 * Sub-shapes:
 * 
 * *include-shape* allow stencils to be rendered within the current stencil by
 * referencing the sub-stencil by name. Attributes are:
 * 
 * - \"name\", required string. The unique shape name of the stencil.
 * - \"x\", \"y\", \"w\", \"h\", required decimals. The (x,y) position of the sub-shape
 * and its width and height.
 * 
 * Constructor: mxStencil
 * 
 * Constructs a new generic shape by setting <desc> to the given XML node and
 * invoking <parseDescription> and <parseConstraints>.
 * 
 * Parameters:
 * 
 * desc - XML node that contains the stencil description.
 */
function mxStencil(desc)
{
\tthis.desc = desc;
\tthis.parseDescription();
\tthis.parseConstraints();
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxStencil, mxShape);

/**
 * Variable: defaultLocalized
 * 
 * Static global variable that specifies the default value for the localized
 * attribute of the text element. Default is false.
 */
mxStencil.defaultLocalized = false;

/**
 * Function: allowEval
 * 
 * Static global switch that specifies if the use of eval is allowed for
 * evaluating text content and images. Default is false. Set this to true
 * if stencils can not contain user input.
 */
mxStencil.allowEval = false;

/**
 * Variable: desc
 *
 * Holds the XML node with the stencil description.
 */
mxStencil.prototype.desc = null;

/**
 * Variable: constraints
 * 
 * Holds an array of <mxConnectionConstraints> as defined in the shape.
 */
mxStencil.prototype.constraints = null;

/**
 * Variable: aspect
 *
 * Holds the aspect of the shape. Default is 'auto'.
 */
mxStencil.prototype.aspect = null;

/**
 * Variable: w0
 *
 * Holds the width of the shape. Default is 100.
 */
mxStencil.prototype.w0 = null;

/**
 * Variable: h0
 *
 * Holds the height of the shape. Default is 100.
 */
mxStencil.prototype.h0 = null;

/**
 * Variable: bgNodes
 *
 * Holds the XML node with the stencil description.
 */
mxStencil.prototype.bgNode = null;

/**
 * Variable: fgNodes
 *
 * Holds the XML node with the stencil description.
 */
mxStencil.prototype.fgNode = null;

/**
 * Variable: strokewidth
 *
 * Holds the strokewidth direction from the description.
 */
mxStencil.prototype.strokewidth = null;

/**
 * Function: parseDescription
 *
 * Reads <w0>, <h0>, <aspect>, <bgNodes> and <fgNodes> from <desc>.
 */
mxStencil.prototype.parseDescription = function()
{
\t// LATER: Preprocess nodes for faster painting
\tthis.fgNode = this.desc.getElementsByTagName('foreground')[0];
\tthis.bgNode = this.desc.getElementsByTagName('background')[0];
\tthis.w0 = Number(this.desc.getAttribute('w') || 100);
\tthis.h0 = Number(this.desc.getAttribute('h') || 100);
\t
\t// Possible values for aspect are: variable and fixed where
\t// variable means fill the available space and fixed means
\t// use w0 and h0 to compute the aspect.
\tvar aspect = this.desc.getAttribute('aspect');
\tthis.aspect = (aspect != null) ? aspect : 'variable';
\t
\t// Possible values for strokewidth are all numbers and \"inherit\"
\t// where the inherit means take the value from the style (ie. the
\t// user-defined stroke-width). Note that the strokewidth is scaled
\t// by the minimum scaling that is used to draw the shape (sx, sy).
\tvar sw = this.desc.getAttribute('strokewidth');
\tthis.strokewidth = (sw != null) ? sw : '1';
};

/**
 * Function: parseConstraints
 *
 * Reads the constraints from <desc> into <constraints> using
 * <parseConstraint>.
 */
mxStencil.prototype.parseConstraints = function()
{
\tvar conns = this.desc.getElementsByTagName('connections')[0];
\t
\tif (conns != null)
\t{
\t\tvar tmp = mxUtils.getChildNodes(conns);
\t\t
\t\tif (tmp != null && tmp.length > 0)
\t\t{
\t\t\tthis.constraints = [];
\t\t\t
\t\t\tfor (var i = 0; i < tmp.length; i++)
\t\t\t{
\t\t\t\tthis.constraints.push(this.parseConstraint(tmp[i]));
\t\t\t}
\t\t}
\t}
};

/**
 * Function: parseConstraint
 *
 * Parses the given XML node and returns its <mxConnectionConstraint>.
 */
mxStencil.prototype.parseConstraint = function(node)
{
\tvar x = Number(node.getAttribute('x'));
\tvar y = Number(node.getAttribute('y'));
\tvar perimeter = node.getAttribute('perimeter') == '1';
\tvar name = node.getAttribute('name');
\t
\treturn new mxConnectionConstraint(new mxPoint(x, y), perimeter, name);
};

/**
 * Function: evaluateTextAttribute
 * 
 * Gets the given attribute as a text. The return value from <evaluateAttribute>
 * is used as a key to <mxResources.get> if the localized attribute in the text
 * node is 1 or if <defaultLocalized> is true.
 */
mxStencil.prototype.evaluateTextAttribute = function(node, attribute, shape)
{
\tvar result = this.evaluateAttribute(node, attribute, shape);
\tvar loc = node.getAttribute('localized');
\t
\tif ((mxStencil.defaultLocalized && loc == null) || loc == '1')
\t{
\t\tresult = mxResources.get(result);
\t}

\treturn result;
};

/**
 * Function: evaluateAttribute
 *
 * Gets the attribute for the given name from the given node. If the attribute
 * does not exist then the text content of the node is evaluated and if it is
 * a function it is invoked with <shape> as the only argument and the return
 * value is used as the attribute value to be returned.
 */
mxStencil.prototype.evaluateAttribute = function(node, attribute, shape)
{
\tvar result = node.getAttribute(attribute);
\t
\tif (result == null)
\t{
\t\tvar text = mxUtils.getTextContent(node);
\t\t
\t\tif (text != null && mxStencil.allowEval)
\t\t{
\t\t\tvar funct = mxUtils.eval(text);
\t\t\t
\t\t\tif (typeof(funct) == 'function')
\t\t\t{
\t\t\t\tresult = funct(shape);
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: drawShape
 *
 * Draws this stencil inside the given bounds.
 */
mxStencil.prototype.drawShape = function(canvas, shape, x, y, w, h)
{
\tvar stack = canvas.states.slice();
\t
\t// TODO: Internal structure (array of special structs?), relative and absolute
\t// coordinates (eg. note shape, process vs star, actor etc.), text rendering
\t// and non-proportional scaling, how to implement pluggable edge shapes
\t// (start, segment, end blocks), pluggable markers, how to implement
\t// swimlanes (title area) with this API, add icon, horizontal/vertical
\t// label, indicator for all shapes, rotation
\tvar direction = mxUtils.getValue(shape.style, mxConstants.STYLE_DIRECTION, null);
\tvar aspect = this.computeAspect(shape.style, x, y, w, h, direction);
\tvar minScale = Math.min(aspect.width, aspect.height);
\tvar sw = (this.strokewidth == 'inherit') ?
\t\t\tNumber(mxUtils.getNumber(shape.style, mxConstants.STYLE_STROKEWIDTH, 1)) :
\t\t\tNumber(this.strokewidth) * minScale;
\tcanvas.setStrokeWidth(sw);

\t// Draws a transparent rectangle for catching events
\tif (shape.style != null && mxUtils.getValue(shape.style, mxConstants.STYLE_POINTER_EVENTS, '0') == '1')
\t{
\t\tcanvas.setStrokeColor(mxConstants.NONE);
\t\tcanvas.rect(x, y, w, h);
\t\tcanvas.stroke();
\t\tcanvas.setStrokeColor(shape.stroke);
\t}

\tthis.drawChildren(canvas, shape, x, y, w, h, this.bgNode, aspect, false, true);
\tthis.drawChildren(canvas, shape, x, y, w, h, this.fgNode, aspect, true,
\t\t!shape.outline || shape.style == null || mxUtils.getValue(
\t\tshape.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0);
\t
\t// Restores stack for unequal count of save/restore calls
\tif (canvas.states.length != stack.length)
\t{
\t\tcanvas.states = stack;
\t}
};

/**
 * Function: drawChildren
 *
 * Draws this stencil inside the given bounds.
 */
mxStencil.prototype.drawChildren = function(canvas, shape, x, y, w, h, node, aspect, disableShadow, paint)
{
\tif (node != null && w > 0 && h > 0)
\t{
\t\tvar tmp = node.firstChild;
\t\t
\t\twhile (tmp != null)
\t\t{
\t\t\tif (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t{
\t\t\t\tthis.drawNode(canvas, shape, tmp, aspect, disableShadow, paint);
\t\t\t}
\t\t\t
\t\t\ttmp = tmp.nextSibling;
\t\t}
\t}
};

/**
 * Function: computeAspect
 *
 * Returns a rectangle that contains the offset in x and y and the horizontal
 * and vertical scale in width and height used to draw this shape inside the
 * given <mxRectangle>.
 * 
 * Parameters:
 * 
 * shape - <mxShape> to be drawn.
 * bounds - <mxRectangle> that should contain the stencil.
 * direction - Optional direction of the shape to be darwn.
 */
mxStencil.prototype.computeAspect = function(shape, x, y, w, h, direction)
{
\tvar x0 = x;
\tvar y0 = y;
\tvar sx = w / this.w0;
\tvar sy = h / this.h0;
\t
\tvar inverse = (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH);

\tif (inverse)
\t{
\t\tsy = w / this.h0;
\t\tsx = h / this.w0;
\t\t
\t\tvar delta = (w - h) / 2;

\t\tx0 += delta;
\t\ty0 -= delta;
\t}

\tif (this.aspect == 'fixed')
\t{
\t\tsy = Math.min(sx, sy);
\t\tsx = sy;
\t\t
\t\t// Centers the shape inside the available space
\t\tif (inverse)
\t\t{
\t\t\tx0 += (h - this.w0 * sx) / 2;
\t\t\ty0 += (w - this.h0 * sy) / 2;
\t\t}
\t\telse
\t\t{
\t\t\tx0 += (w - this.w0 * sx) / 2;
\t\t\ty0 += (h - this.h0 * sy) / 2;
\t\t}
\t}

\treturn new mxRectangle(x0, y0, sx, sy);
};

/**
 * Function: drawNode
 *
 * Draws this stencil inside the given bounds.
 */
mxStencil.prototype.drawNode = function(canvas, shape, node, aspect, disableShadow, paint)
{
\tvar name = node.nodeName;
\tvar x0 = aspect.x;
\tvar y0 = aspect.y;
\tvar sx = aspect.width;
\tvar sy = aspect.height;
\tvar minScale = Math.min(sx, sy);
\t
\tif (name == 'save')
\t{
\t\tcanvas.save();
\t}
\telse if (name == 'restore')
\t{
\t\tcanvas.restore();
\t}
\telse if (paint)
\t{
\t\tif (name == 'path')
\t\t{
\t\t\tcanvas.begin();
\t\t\t
\t\t\tvar parseRegularly = true;
\t\t\t
\t\t\tif (node.getAttribute('rounded') == '1')
\t\t\t{
\t\t\t\tparseRegularly = false;
\t\t\t\t
\t\t\t\tvar arcSize = Number(node.getAttribute('arcSize'));
\t\t\t\tvar pointCount = 0;
\t\t\t\tvar segs = [];
\t\t\t\t
\t\t\t\t// Renders the elements inside the given path
\t\t\t\tvar childNode = node.firstChild;
\t\t\t\t
\t\t\t\twhile (childNode != null)
\t\t\t\t{
\t\t\t\t\tif (childNode.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t\t\t{
\t\t\t\t\t\tvar childName = childNode.nodeName;
\t\t\t\t\t\t
\t\t\t\t\t\tif (childName == 'move' || childName == 'line')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (childName == 'move' || segs.length == 0)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tsegs.push([]);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tsegs[segs.length - 1].push(new mxPoint(x0 + Number(childNode.getAttribute('x')) * sx,
\t\t\t\t\t\t\t\ty0 + Number(childNode.getAttribute('y')) * sy));
\t\t\t\t\t\t\tpointCount++;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\t//We only support move and line for rounded corners
\t\t\t\t\t\t\tparseRegularly = true;
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tchildNode = childNode.nextSibling;
\t\t\t\t}

\t\t\t\tif (!parseRegularly && pointCount > 0)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < segs.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar close = false, ps = segs[i][0], pe = segs[i][segs[i].length - 1];
\t\t\t\t\t\t
\t\t\t\t\t\tif (ps.x == pe.x && ps.y == pe.y) 
\t\t\t\t\t\t{
\t\t\t\t\t\t\tsegs[i].pop();
\t\t\t\t\t\t\tclose = true;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tthis.addPoints(canvas, segs[i], true, arcSize, close);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tparseRegularly = true;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (parseRegularly)
\t\t\t{
\t\t\t\t// Renders the elements inside the given path
\t\t\t\tvar childNode = node.firstChild;
\t\t\t\t
\t\t\t\twhile (childNode != null)
\t\t\t\t{
\t\t\t\t\tif (childNode.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t\t\t{
\t\t\t\t\t\tthis.drawNode(canvas, shape, childNode, aspect, disableShadow, paint);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tchildNode = childNode.nextSibling;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (name == 'close')
\t\t{
\t\t\tcanvas.close();
\t\t}
\t\telse if (name == 'move')
\t\t{
\t\t\tcanvas.moveTo(x0 + Number(node.getAttribute('x')) * sx, y0 + Number(node.getAttribute('y')) * sy);
\t\t}
\t\telse if (name == 'line')
\t\t{
\t\t\tcanvas.lineTo(x0 + Number(node.getAttribute('x')) * sx, y0 + Number(node.getAttribute('y')) * sy);
\t\t}
\t\telse if (name == 'quad')
\t\t{
\t\t\tcanvas.quadTo(x0 + Number(node.getAttribute('x1')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y1')) * sy,
\t\t\t\t\tx0 + Number(node.getAttribute('x2')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y2')) * sy);
\t\t}
\t\telse if (name == 'curve')
\t\t{
\t\t\tcanvas.curveTo(x0 + Number(node.getAttribute('x1')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y1')) * sy,
\t\t\t\t\tx0 + Number(node.getAttribute('x2')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y2')) * sy,
\t\t\t\t\tx0 + Number(node.getAttribute('x3')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y3')) * sy);
\t\t}
\t\telse if (name == 'arc')
\t\t{
\t\t\tcanvas.arcTo(Number(node.getAttribute('rx')) * sx,
\t\t\t\t\tNumber(node.getAttribute('ry')) * sy,
\t\t\t\t\tNumber(node.getAttribute('x-axis-rotation')),
\t\t\t\t\tNumber(node.getAttribute('large-arc-flag')),
\t\t\t\t\tNumber(node.getAttribute('sweep-flag')),
\t\t\t\t\tx0 + Number(node.getAttribute('x')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y')) * sy);
\t\t}
\t\telse if (name == 'rect')
\t\t{
\t\t\tcanvas.rect(x0 + Number(node.getAttribute('x')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y')) * sy,
\t\t\t\t\tNumber(node.getAttribute('w')) * sx,
\t\t\t\t\tNumber(node.getAttribute('h')) * sy);
\t\t}
\t\telse if (name == 'roundrect')
\t\t{
\t\t\tvar arcsize = Number(node.getAttribute('arcsize'));
\t
\t\t\tif (arcsize == 0)
\t\t\t{
\t\t\t\tarcsize = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100;
\t\t\t}
\t\t\t
\t\t\tvar w = Number(node.getAttribute('w')) * sx;
\t\t\tvar h = Number(node.getAttribute('h')) * sy;
\t\t\tvar factor = Number(arcsize) / 100;
\t\t\tvar r = Math.min(w * factor, h * factor);
\t\t\t
\t\t\tcanvas.roundrect(x0 + Number(node.getAttribute('x')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y')) * sy,
\t\t\t\t\tw, h, r, r);
\t\t}
\t\telse if (name == 'ellipse')
\t\t{
\t\t\tcanvas.ellipse(x0 + Number(node.getAttribute('x')) * sx,
\t\t\t\ty0 + Number(node.getAttribute('y')) * sy,
\t\t\t\tNumber(node.getAttribute('w')) * sx,
\t\t\t\tNumber(node.getAttribute('h')) * sy);
\t\t}
\t\telse if (name == 'image')
\t\t{
\t\t\tif (!shape.outline)
\t\t\t{
\t\t\t\tvar src = this.evaluateAttribute(node, 'src', shape);
\t\t\t\t
\t\t\t\tcanvas.image(x0 + Number(node.getAttribute('x')) * sx,
\t\t\t\t\ty0 + Number(node.getAttribute('y')) * sy,
\t\t\t\t\tNumber(node.getAttribute('w')) * sx,
\t\t\t\t\tNumber(node.getAttribute('h')) * sy,
\t\t\t\t\tsrc, false, node.getAttribute('flipH') == '1',
\t\t\t\t\tnode.getAttribute('flipV') == '1');
\t\t\t}
\t\t}
\t\telse if (name == 'text')
\t\t{
\t\t\tif (!shape.outline)
\t\t\t{
\t\t\t\tvar str = this.evaluateTextAttribute(node, 'str', shape);
\t\t\t\tvar rotation = node.getAttribute('vertical') == '1' ? -90 : 0;
\t\t\t\t
\t\t\t\tif (node.getAttribute('align-shape') == '0')
\t\t\t\t{
\t\t\t\t\tvar dr = shape.rotation;
\t\t
\t\t\t\t\t// Depends on flipping
\t\t\t\t\tvar flipH = mxUtils.getValue(shape.style, mxConstants.STYLE_FLIPH, 0) == 1;
\t\t\t\t\tvar flipV = mxUtils.getValue(shape.style, mxConstants.STYLE_FLIPV, 0) == 1;
\t\t\t\t\t
\t\t\t\t\tif (flipH && flipV)
\t\t\t\t\t{
\t\t\t\t\t\trotation -= dr;
\t\t\t\t\t}
\t\t\t\t\telse if (flipH || flipV)
\t\t\t\t\t{
\t\t\t\t\t\trotation += dr;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\trotation -= dr;
\t\t\t\t\t}
\t\t\t\t}
\t\t
\t\t\t\trotation -= node.getAttribute('rotation');
\t\t
\t\t\t\tcanvas.text(x0 + Number(node.getAttribute('x')) * sx,
\t\t\t\t\t\ty0 + Number(node.getAttribute('y')) * sy,
\t\t\t\t\t\t0, 0, str, node.getAttribute('align') || 'left',
\t\t\t\t\t\tnode.getAttribute('valign') || 'top', false, '',
\t\t\t\t\t\tnull, false, rotation);
\t\t\t}
\t\t}
\t\telse if (name == 'include-shape')
\t\t{
\t\t\tvar stencil = mxStencilRegistry.getStencil(node.getAttribute('name'));
\t\t\t
\t\t\tif (stencil != null)
\t\t\t{
\t\t\t\tvar x = x0 + Number(node.getAttribute('x')) * sx;
\t\t\t\tvar y = y0 + Number(node.getAttribute('y')) * sy;
\t\t\t\tvar w = Number(node.getAttribute('w')) * sx;
\t\t\t\tvar h = Number(node.getAttribute('h')) * sy;
\t\t\t\t
\t\t\t\tstencil.drawShape(canvas, shape, x, y, w, h);
\t\t\t}
\t\t}
\t\telse if (name == 'fillstroke')
\t\t{
\t\t\tcanvas.fillAndStroke();
\t\t}
\t\telse if (name == 'fill')
\t\t{
\t\t\tcanvas.fill();
\t\t}
\t\telse if (name == 'stroke')
\t\t{
\t\t\tcanvas.stroke();
\t\t}
\t\telse if (name == 'strokewidth')
\t\t{
\t\t\tvar s = (node.getAttribute('fixed') == '1') ? 1 : minScale;
\t\t\tcanvas.setStrokeWidth(Number(node.getAttribute('width')) * s);
\t\t}
\t\telse if (name == 'dashed')
\t\t{
\t\t\tcanvas.setDashed(node.getAttribute('dashed') == '1');
\t\t}
\t\telse if (name == 'dashpattern')
\t\t{
\t\t\tvar value = node.getAttribute('pattern');
\t\t\t
\t\t\tif (value != null)
\t\t\t{
\t\t\t\tvar tmp = value.split(' ');
\t\t\t\tvar pat = [];
\t\t\t\t
\t\t\t\tfor (var i = 0; i < tmp.length; i++)
\t\t\t\t{
\t\t\t\t\tif (tmp[i].length > 0)
\t\t\t\t\t{
\t\t\t\t\t\tpat.push(Number(tmp[i]) * minScale);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tvalue = pat.join(' ');
\t\t\t\tcanvas.setDashPattern(value);
\t\t\t}
\t\t}
\t\telse if (name == 'strokecolor')
\t\t{
\t\t\tcanvas.setStrokeColor(node.getAttribute('color'));
\t\t}
\t\telse if (name == 'linecap')
\t\t{
\t\t\tcanvas.setLineCap(node.getAttribute('cap'));
\t\t}
\t\telse if (name == 'linejoin')
\t\t{
\t\t\tcanvas.setLineJoin(node.getAttribute('join'));
\t\t}
\t\telse if (name == 'miterlimit')
\t\t{
\t\t\tcanvas.setMiterLimit(Number(node.getAttribute('limit')));
\t\t}
\t\telse if (name == 'fillcolor')
\t\t{
\t\t\tcanvas.setFillColor(node.getAttribute('color'));
\t\t}
\t\telse if (name == 'alpha')
\t\t{
\t\t\tcanvas.setAlpha(node.getAttribute('alpha'));
\t\t}
\t\telse if (name == 'fillalpha')
\t\t{
\t\t\tcanvas.setAlpha(node.getAttribute('alpha'));
\t\t}
\t\telse if (name == 'strokealpha')
\t\t{
\t\t\tcanvas.setAlpha(node.getAttribute('alpha'));
\t\t}
\t\telse if (name == 'fontcolor')
\t\t{
\t\t\tcanvas.setFontColor(node.getAttribute('color'));
\t\t}
\t\telse if (name == 'fontstyle')
\t\t{
\t\t\tcanvas.setFontStyle(node.getAttribute('style'));
\t\t}
\t\telse if (name == 'fontfamily')
\t\t{
\t\t\tcanvas.setFontFamily(node.getAttribute('family'));
\t\t}
\t\telse if (name == 'fontsize')
\t\t{
\t\t\tcanvas.setFontSize(Number(node.getAttribute('size')) * minScale);
\t\t}
\t\t
\t\tif (disableShadow && (name == 'fillstroke' || name == 'fill' || name == 'stroke'))
\t\t{
\t\t\tdisableShadow = false;
\t\t\tcanvas.setShadow(false);
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 * 
 * Code to add stencils.
 * 
 * (code)
 * var req = mxUtils.load('test/stencils.xml');
 * var root = req.getDocumentElement();
 * var shape = root.firstChild;
 * 
 * while (shape != null)
 * {
 * \t if (shape.nodeType == mxConstants.NODETYPE_ELEMENT)
 *   {
 *     mxStencilRegistry.addStencil(shape.getAttribute('name'), new mxStencil(shape));
 *   }
 *   
 *   shape = shape.nextSibling;
 * }
 * (end)
 */
var mxStencilRegistry =
{
\t/**
\t * Class: mxStencilRegistry
\t * 
\t * A singleton class that provides a registry for stencils and the methods
\t * for painting those stencils onto a canvas or into a DOM.
\t */
\tstencils: {},
\t
\t/**
\t * Function: addStencil
\t * 
\t * Adds the given <mxStencil>.
\t */
\taddStencil: function(name, stencil)
\t{
\t\tmxStencilRegistry.stencils[name] = stencil;
\t},
\t
\t/**
\t * Function: getStencil
\t * 
\t * Returns the <mxStencil> for the given name.
\t */
\tgetStencil: function(name)
\t{
\t\treturn mxStencilRegistry.stencils[name];
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxMarker =
{
\t/**
\t * Class: mxMarker
\t * 
\t * A static class that implements all markers for VML and SVG using a
\t * registry. NOTE: The signatures in this class will change.
\t * 
\t * Variable: markers
\t * 
\t * Maps from markers names to functions to paint the markers.
\t */
\tmarkers: [],
\t
\t/**
\t * Function: addMarker
\t * 
\t * Adds a factory method that updates a given endpoint and returns a
\t * function to paint the marker onto the given canvas.
\t */
\taddMarker: function(type, funct)
\t{
\t\tmxMarker.markers[type] = funct;
\t},
\t
\t/**
\t * Function: createMarker
\t * 
\t * Returns a function to paint the given marker.
\t */
\tcreateMarker: function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
\t{
\t\tvar funct = mxMarker.markers[type];
\t\t
\t\treturn (funct != null) ? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) : null;
\t}

};

/**
 * Adds the classic and block marker factory method.
 */
(function()
{
\tfunction createArrow(widthFactor)
\t{
\t\twidthFactor = (widthFactor != null) ? widthFactor : 2;
\t\t
\t\treturn function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
\t\t{
\t\t\t// The angle of the forward facing arrow sides against the x axis is
\t\t\t// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
\t\t\t// only half the strokewidth is processed ).
\t\t\tvar endOffsetX = unitX * sw * 1.118;
\t\t\tvar endOffsetY = unitY * sw * 1.118;
\t\t\t
\t\t\tunitX = unitX * (size + sw);
\t\t\tunitY = unitY * (size + sw);
\t
\t\t\tvar pt = pe.clone();
\t\t\tpt.x -= endOffsetX;
\t\t\tpt.y -= endOffsetY;
\t\t\t
\t\t\tvar f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
\t\t\tpe.x += -unitX * f - endOffsetX;
\t\t\tpe.y += -unitY * f - endOffsetY;
\t\t\t
\t\t\treturn function()
\t\t\t{
\t\t\t\tcanvas.begin();
\t\t\t\tcanvas.moveTo(pt.x, pt.y);
\t\t\t\tcanvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
\t\t\t
\t\t\t\tif (type == mxConstants.ARROW_CLASSIC || type == mxConstants.ARROW_CLASSIC_THIN)
\t\t\t\t{
\t\t\t\t\tcanvas.lineTo(pt.x - unitX * 3 / 4, pt.y - unitY * 3 / 4);
\t\t\t\t}
\t\t\t
\t\t\t\tcanvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
\t\t\t\tcanvas.close();
\t
\t\t\t\tif (filled)
\t\t\t\t{
\t\t\t\t\tcanvas.fillAndStroke();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tcanvas.stroke();
\t\t\t\t}
\t\t\t};
\t\t}
\t};
\t
\tmxMarker.addMarker('classic', createArrow(2));
\tmxMarker.addMarker('classicThin', createArrow(3));
\tmxMarker.addMarker('block', createArrow(2));
\tmxMarker.addMarker('blockThin', createArrow(3));
\t
\tfunction createOpenArrow(widthFactor)
\t{
\t\twidthFactor = (widthFactor != null) ? widthFactor : 2;
\t\t
\t\treturn function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
\t\t{
\t\t\t// The angle of the forward facing arrow sides against the x axis is
\t\t\t// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
\t\t\t// only half the strokewidth is processed ).
\t\t\tvar endOffsetX = unitX * sw * 1.118;
\t\t\tvar endOffsetY = unitY * sw * 1.118;
\t\t\t
\t\t\tunitX = unitX * (size + sw);
\t\t\tunitY = unitY * (size + sw);
\t\t\t
\t\t\tvar pt = pe.clone();
\t\t\tpt.x -= endOffsetX;
\t\t\tpt.y -= endOffsetY;
\t\t\t
\t\t\tpe.x += -endOffsetX * 2;
\t\t\tpe.y += -endOffsetY * 2;

\t\t\treturn function()
\t\t\t{
\t\t\t\tcanvas.begin();
\t\t\t\tcanvas.moveTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
\t\t\t\tcanvas.lineTo(pt.x, pt.y);
\t\t\t\tcanvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
\t\t\t\tcanvas.stroke();
\t\t\t};
\t\t}
\t};
\t
\tmxMarker.addMarker('open', createOpenArrow(2));
\tmxMarker.addMarker('openThin', createOpenArrow(3));
\t
\tmxMarker.addMarker('oval', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
\t{
\t\tvar a = size / 2;
\t\t
\t\tvar pt = pe.clone();
\t\tpe.x -= unitX * a;
\t\tpe.y -= unitY * a;

\t\treturn function()
\t\t{
\t\t\tcanvas.ellipse(pt.x - a, pt.y - a, size, size);
\t\t\t\t\t\t
\t\t\tif (filled)
\t\t\t{
\t\t\t\tcanvas.fillAndStroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tcanvas.stroke();
\t\t\t}
\t\t};
\t});

\tfunction diamond(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
\t{
\t\t// The angle of the forward facing arrow sides against the x axis is
\t\t// 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for
\t\t// only half the strokewidth is processed ). Or 0.9862 for thin diamond.
\t\t// Note these values and the tk variable below are dependent, update
\t\t// both together (saves trig hard coding it).
\t\tvar swFactor = (type == mxConstants.ARROW_DIAMOND) ?  0.7071 : 0.9862;
\t\tvar endOffsetX = unitX * sw * swFactor;
\t\tvar endOffsetY = unitY * sw * swFactor;
\t\t
\t\tunitX = unitX * (size + sw);
\t\tunitY = unitY * (size + sw);
\t\t
\t\tvar pt = pe.clone();
\t\tpt.x -= endOffsetX;
\t\tpt.y -= endOffsetY;
\t\t
\t\tpe.x += -unitX - endOffsetX;
\t\tpe.y += -unitY - endOffsetY;
\t\t
\t\t// thickness factor for diamond
\t\tvar tk = ((type == mxConstants.ARROW_DIAMOND) ?  2 : 3.4);
\t\t
\t\treturn function()
\t\t{
\t\t\tcanvas.begin();
\t\t\tcanvas.moveTo(pt.x, pt.y);
\t\t\tcanvas.lineTo(pt.x - unitX / 2 - unitY / tk, pt.y + unitX / tk - unitY / 2);
\t\t\tcanvas.lineTo(pt.x - unitX, pt.y - unitY);
\t\t\tcanvas.lineTo(pt.x - unitX / 2 + unitY / tk, pt.y - unitY / 2 - unitX / tk);
\t\t\tcanvas.close();
\t\t\t
\t\t\tif (filled)
\t\t\t{
\t\t\t\tcanvas.fillAndStroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tcanvas.stroke();
\t\t\t}
\t\t};
\t};

\tmxMarker.addMarker('diamond', diamond);
\tmxMarker.addMarker('diamondThin', diamond);
})();
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxActor
 *
 * Extends <mxShape> to implement an actor shape. If a custom shape with one
 * filled area is needed, then this shape's <redrawPath> should be overridden.
 * 
 * Example:
 * 
 * (code)
 * function SampleShape() { }
 * 
 * SampleShape.prototype = new mxActor();
 * SampleShape.prototype.constructor = vsAseShape;
 * 
 * mxCellRenderer.registerShape('sample', SampleShape);
 * SampleShape.prototype.redrawPath = function(path, x, y, w, h)
 * {
 *   path.moveTo(0, 0);
 *   path.lineTo(w, h);
 *   // ...
 *   path.close();
 * }
 * (end)
 * 
 * This shape is registered under <mxConstants.SHAPE_ACTOR> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxActor
 *
 * Constructs a new actor shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxActor(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxActor, mxShape);

/**
 * Function: paintVertexShape
 * 
 * Redirects to redrawPath for subclasses to work.
 */
mxActor.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tc.translate(x, y);
\tc.begin();
\tthis.redrawPath(c, x, y, w, h);
\tc.fillAndStroke();
};

/**
 * Function: redrawPath
 *
 * Draws the path for this shape.
 */
mxActor.prototype.redrawPath = function(c, x, y, w, h)
{
\tvar width = w/3;
\tc.moveTo(0, h);
\tc.curveTo(0, 3 * h / 5, 0, 2 * h / 5, w / 2, 2 * h / 5);
\tc.curveTo(w / 2 - width, 2 * h / 5, w / 2 - width, 0, w / 2, 0);
\tc.curveTo(w / 2 + width, 0, w / 2 + width, 2 * h / 5, w / 2, 2 * h / 5);
\tc.curveTo(w, 2 * h / 5, w, 3 * h / 5, w, h);
\tc.close();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCloud
 *
 * Extends <mxActor> to implement a cloud shape.
 * 
 * This shape is registered under <mxConstants.SHAPE_CLOUD> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxCloud
 *
 * Constructs a new cloud shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxCloud(bounds, fill, stroke, strokewidth)
{
\tmxActor.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxActor.
 */
mxUtils.extend(mxCloud, mxActor);

/**
 * Function: redrawPath
 *
 * Draws the path for this shape.
 */
mxCloud.prototype.redrawPath = function(c, x, y, w, h)
{
\tc.moveTo(0.25 * w, 0.25 * h);
\tc.curveTo(0.05 * w, 0.25 * h, 0, 0.5 * h, 0.16 * w, 0.55 * h);
\tc.curveTo(0, 0.66 * h, 0.18 * w, 0.9 * h, 0.31 * w, 0.8 * h);
\tc.curveTo(0.4 * w, h, 0.7 * w, h, 0.8 * w, 0.8 * h);
\tc.curveTo(w, 0.8 * h, w, 0.6 * h, 0.875 * w, 0.5 * h);
\tc.curveTo(w, 0.3 * h, 0.8 * w, 0.1 * h, 0.625 * w, 0.2 * h);
\tc.curveTo(0.5 * w, 0.05 * h, 0.3 * w, 0.05 * h, 0.25 * w, 0.25 * h);
\tc.close();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxRectangleShape
 *
 * Extends <mxShape> to implement a rectangle shape.
 * This shape is registered under <mxConstants.SHAPE_RECTANGLE>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxRectangleShape
 *
 * Constructs a new rectangle shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxRectangleShape(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxRectangleShape, mxShape);

/**
 * Function: isHtmlAllowed
 *
 * Returns true for non-rounded, non-rotated shapes with no glass gradient.
 */
mxRectangleShape.prototype.isHtmlAllowed = function()
{
\tvar events = true;
\t
\tif (this.style != null)
\t{
\t\tevents = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';\t\t
\t}
\t
\treturn !this.isRounded && !this.glass && this.rotation == 0 && (events ||
\t\t(this.fill != null && this.fill != mxConstants.NONE));
};

/**
 * Function: paintBackground
 * 
 * Generic background painting implementation.
 */
mxRectangleShape.prototype.paintBackground = function(c, x, y, w, h)
{
\tvar events = true;
\t
\tif (this.style != null)
\t{
\t\tevents = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
\t}
\t
\tif (events || (this.fill != null && this.fill != mxConstants.NONE) ||
\t\t(this.stroke != null && this.stroke != mxConstants.NONE))
\t{
\t\tif (!events && (this.fill == null || this.fill == mxConstants.NONE))
\t\t{
\t\t\tc.pointerEvents = false;
\t\t}
\t\t
\t\tif (this.isRounded)
\t\t{
\t\t\tvar r = 0;
\t\t\t
\t\t\tif (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
\t\t\t{
\t\t\t\tr = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
\t\t\t\t\tmxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
\t\t\t\t\tmxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
\t\t\t\tr = Math.min(w * f, h * f);
\t\t\t}
\t\t\t
\t\t\tc.roundrect(x, y, w, h, r, r);
\t\t}
\t\telse
\t\t{
\t\t\tc.rect(x, y, w, h);
\t\t}
\t\t\t
\t\tc.fillAndStroke();
\t}
};

/**
 * Function: isRoundable
 * 
 * Adds roundable support.
 */
mxRectangleShape.prototype.isRoundable = function(c, x, y, w, h)
{
\treturn true;
};

/**
 * Function: paintForeground
 * 
 * Generic background painting implementation.
 */
mxRectangleShape.prototype.paintForeground = function(c, x, y, w, h)
{
\tif (this.glass && !this.outline && this.fill != null && this.fill != mxConstants.NONE)
\t{
\t\tthis.paintGlassEffect(c, x, y, w, h, this.getArcSize(w + this.strokewidth, h + this.strokewidth));
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxEllipse
 *
 * Extends <mxShape> to implement an ellipse shape.
 * This shape is registered under <mxConstants.SHAPE_ELLIPSE>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxEllipse
 *
 * Constructs a new ellipse shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxEllipse(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxEllipse, mxShape);

/**
 * Function: paintVertexShape
 * 
 * Paints the ellipse shape.
 */
mxEllipse.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tc.ellipse(x, y, w, h);
\tc.fillAndStroke();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDoubleEllipse
 *
 * Extends <mxShape> to implement a double ellipse shape. This shape is
 * registered under <mxConstants.SHAPE_DOUBLE_ELLIPSE> in <mxCellRenderer>.
 * Use the following override to only fill the inner ellipse in this shape:
 * 
 * (code)
 * mxDoubleEllipse.prototype.paintVertexShape = function(c, x, y, w, h)
 * {
 *   c.ellipse(x, y, w, h);
 *   c.stroke();
 *   
 *   var inset = mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5)));
 *   x += inset;
 *   y += inset;
 *   w -= 2 * inset;
 *   h -= 2 * inset;
 *   
 *   if (w > 0 && h > 0)
 *   {
 *     c.ellipse(x, y, w, h);
 *   }
 *   
 *   c.fillAndStroke();
 * };
 * (end)
 * 
 * Constructor: mxDoubleEllipse
 *
 * Constructs a new ellipse shape.
 *
 * Parameters:
 *
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxDoubleEllipse(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxDoubleEllipse, mxShape);

/**
 * Variable: vmlScale
 * 
 * Scale for improving the precision of VML rendering. Default is 10.
 */
mxDoubleEllipse.prototype.vmlScale = 10;

/**
 * Function: paintBackground
 * 
 * Paints the background.
 */
mxDoubleEllipse.prototype.paintBackground = function(c, x, y, w, h)
{
\tc.ellipse(x, y, w, h);
\tc.fillAndStroke();
};

/**
 * Function: paintForeground
 * 
 * Paints the foreground.
 */
mxDoubleEllipse.prototype.paintForeground = function(c, x, y, w, h)
{
\tif (!this.outline)
\t{
\t\tvar margin = mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5)));
\t\tx += margin;
\t\ty += margin;
\t\tw -= 2 * margin;
\t\th -= 2 * margin;
\t\t
\t\t// FIXME: Rounding issues in IE8 standards mode (not in 1.x)
\t\tif (w > 0 && h > 0)
\t\t{
\t\t\tc.ellipse(x, y, w, h);
\t\t}
\t\t
\t\tc.stroke();
\t}
};

/**
 * Function: getLabelBounds
 * 
 * Returns the bounds for the label.
 */
mxDoubleEllipse.prototype.getLabelBounds = function(rect)
{
\tvar margin = (mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth,
\t\t\tMath.min(rect.width / 5 / this.scale, rect.height / 5 / this.scale)))) * this.scale;

\treturn new mxRectangle(rect.x + margin, rect.y + margin, rect.width - 2 * margin, rect.height - 2 * margin);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxRhombus
 *
 * Extends <mxShape> to implement a rhombus (aka diamond) shape.
 * This shape is registered under <mxConstants.SHAPE_RHOMBUS>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxRhombus
 *
 * Constructs a new rhombus shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxRhombus(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxRhombus, mxShape);

/**
 * Function: isRoundable
 * 
 * Adds roundable support.
 */
mxRhombus.prototype.isRoundable = function()
{
\treturn true;
};

/**
 * Function: paintVertexShape
 * 
 * Generic painting implementation.
 */
mxRhombus.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tvar hw = w / 2;
\tvar hh = h / 2;
\t
\tvar arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
\tc.begin();
\tthis.addPoints(c, [new mxPoint(x + hw, y), new mxPoint(x + w, y + hh), new mxPoint(x + hw, y + h),
\t     new mxPoint(x, y + hh)], this.isRounded, arcSize, true);
\tc.fillAndStroke();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPolyline
 *
 * Extends <mxShape> to implement a polyline (a line with multiple points).
 * This shape is registered under <mxConstants.SHAPE_POLYLINE> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxPolyline
 *
 * Constructs a new polyline shape.
 * 
 * Parameters:
 * 
 * points - Array of <mxPoints> that define the points. This is stored in
 * <mxShape.points>.
 * stroke - String that defines the stroke color. Default is 'black'. This is
 * stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxPolyline(points, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.points = points;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxPolyline, mxShape);

/**
 * Function: getRotation
 * 
 * Returns 0.
 */
mxPolyline.prototype.getRotation = function()
{
\treturn 0;
};

/**
 * Function: getShapeRotation
 * 
 * Returns 0.
 */
mxPolyline.prototype.getShapeRotation = function()
{
\treturn 0;
};

/**
 * Function: isPaintBoundsInverted
 * 
 * Returns false.
 */
mxPolyline.prototype.isPaintBoundsInverted = function()
{
\treturn false;
};

/**
 * Function: paintEdgeShape
 * 
 * Paints the line shape.
 */
mxPolyline.prototype.paintEdgeShape = function(c, pts)
{
\tvar prev = c.pointerEventsValue;
\tc.pointerEventsValue = 'stroke';
\t
\tif (this.style == null || this.style[mxConstants.STYLE_CURVED] != 1)
\t{
\t\tthis.paintLine(c, pts, this.isRounded);
\t}
\telse
\t{
\t\tthis.paintCurvedLine(c, pts);
\t}
\t
\tc.pointerEventsValue = prev;
};

/**
 * Function: paintLine
 * 
 * Paints the line shape.
 */
mxPolyline.prototype.paintLine = function(c, pts, rounded)
{
\tvar arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
\tc.begin();
\tthis.addPoints(c, pts, rounded, arcSize, false);
\tc.stroke();
};

/**
 * Function: paintCurvedLine
 * 
 * Paints a curved line.
 */
mxPolyline.prototype.paintCurvedLine = function(c, pts)
{
\tc.begin();
\t
\tvar pt = pts[0];
\tvar n = pts.length;
\t
\tc.moveTo(pt.x, pt.y);
\t
\tfor (var i = 1; i < n - 2; i++)
\t{
\t\tvar p0 = pts[i];
\t\tvar p1 = pts[i + 1];
\t\tvar ix = (p0.x + p1.x) / 2;
\t\tvar iy = (p0.y + p1.y) / 2;
\t\t
\t\tc.quadTo(p0.x, p0.y, ix, iy);
\t}
\t
\tvar p0 = pts[n - 2];
\tvar p1 = pts[n - 1];
\t
\tc.quadTo(p0.x, p0.y, p1.x, p1.y);
\tc.stroke();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxArrow
 *
 * Extends <mxShape> to implement an arrow shape. (The shape
 * is used to represent edges, not vertices.)
 * This shape is registered under <mxConstants.SHAPE_ARROW>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxArrow
 *
 * Constructs a new arrow shape.
 * 
 * Parameters:
 * 
 * points - Array of <mxPoints> that define the points. This is stored in
 * <mxShape.points>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 * arrowWidth - Optional integer that defines the arrow width. Default is
 * <mxConstants.ARROW_WIDTH>. This is stored in <arrowWidth>.
 * spacing - Optional integer that defines the spacing between the arrow shape
 * and its endpoints. Default is <mxConstants.ARROW_SPACING>. This is stored in
 * <spacing>.
 * endSize - Optional integer that defines the size of the arrowhead. Default
 * is <mxConstants.ARROW_SIZE>. This is stored in <endSize>.
 */
function mxArrow(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize)
{
\tmxShape.call(this);
\tthis.points = points;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
\tthis.arrowWidth = (arrowWidth != null) ? arrowWidth : mxConstants.ARROW_WIDTH;
\tthis.spacing = (spacing != null) ? spacing : mxConstants.ARROW_SPACING;
\tthis.endSize = (endSize != null) ? endSize : mxConstants.ARROW_SIZE;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxArrow, mxShape);

/**
 * Function: augmentBoundingBox
 *
 * Augments the bounding box with the edge width and markers.
 */
mxArrow.prototype.augmentBoundingBox = function(bbox)
{
\tmxShape.prototype.augmentBoundingBox.apply(this, arguments);
\t
\tvar w = Math.max(this.arrowWidth, this.endSize);
\tbbox.grow((w / 2 + this.strokewidth) * this.scale);
};

/**
 * Function: paintEdgeShape
 * 
 * Paints the line shape.
 */
mxArrow.prototype.paintEdgeShape = function(c, pts)
{
\t// Geometry of arrow
\tvar spacing =  mxConstants.ARROW_SPACING;
\tvar width = mxConstants.ARROW_WIDTH;
\tvar arrow = mxConstants.ARROW_SIZE;

\t// Base vector (between end points)
\tvar p0 = pts[0];
\tvar pe = pts[pts.length - 1];
\tvar dx = pe.x - p0.x;
\tvar dy = pe.y - p0.y;
\tvar dist = Math.sqrt(dx * dx + dy * dy);
\tvar length = dist - 2 * spacing - arrow;
\t
\t// Computes the norm and the inverse norm
\tvar nx = dx / dist;
\tvar ny = dy / dist;
\tvar basex = length * nx;
\tvar basey = length * ny;
\tvar floorx = width * ny/3;
\tvar floory = -width * nx/3;
\t
\t// Computes points
\tvar p0x = p0.x - floorx / 2 + spacing * nx;
\tvar p0y = p0.y - floory / 2 + spacing * ny;
\tvar p1x = p0x + floorx;
\tvar p1y = p0y + floory;
\tvar p2x = p1x + basex;
\tvar p2y = p1y + basey;
\tvar p3x = p2x + floorx;
\tvar p3y = p2y + floory;
\t// p4 not necessary
\tvar p5x = p3x - 3 * floorx;
\tvar p5y = p3y - 3 * floory;
\t
\tc.begin();
\tc.moveTo(p0x, p0y);
\tc.lineTo(p1x, p1y);
\tc.lineTo(p2x, p2y);
\tc.lineTo(p3x, p3y);
\tc.lineTo(pe.x - spacing * nx, pe.y - spacing * ny);
\tc.lineTo(p5x, p5y);
\tc.lineTo(p5x + floorx, p5y + floory);
\tc.close();

\tc.fillAndStroke();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxArrowConnector
 *
 * Extends <mxShape> to implement an new rounded arrow shape with support for
 * waypoints and double arrows. (The shape is used to represent edges, not
 * vertices.) This shape is registered under <mxConstants.SHAPE_ARROW_CONNECTOR>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxArrowConnector
 *
 * Constructs a new arrow shape.
 * 
 * Parameters:
 * 
 * points - Array of <mxPoints> that define the points. This is stored in
 * <mxShape.points>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 * arrowWidth - Optional integer that defines the arrow width. Default is
 * <mxConstants.ARROW_WIDTH>. This is stored in <arrowWidth>.
 * spacing - Optional integer that defines the spacing between the arrow shape
 * and its endpoints. Default is <mxConstants.ARROW_SPACING>. This is stored in
 * <spacing>.
 * endSize - Optional integer that defines the size of the arrowhead. Default
 * is <mxConstants.ARROW_SIZE>. This is stored in <endSize>.
 */
function mxArrowConnector(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize)
{
\tmxShape.call(this);
\tthis.points = points;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
\tthis.arrowWidth = (arrowWidth != null) ? arrowWidth : mxConstants.ARROW_WIDTH;
\tthis.arrowSpacing = (spacing != null) ? spacing : mxConstants.ARROW_SPACING;
\tthis.startSize = mxConstants.ARROW_SIZE / 5;
\tthis.endSize = mxConstants.ARROW_SIZE / 5;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxArrowConnector, mxShape);

/**
 * Variable: useSvgBoundingBox
 * 
 * Allows to use the SVG bounding box in SVG. Default is false for performance
 * reasons.
 */
mxArrowConnector.prototype.useSvgBoundingBox = true;

/**
 * Function: isRoundable
 * 
 * Hook for subclassers.
 */
mxArrowConnector.prototype.isRoundable = function()
{
\treturn true;
};

/**
 * Variable: resetStyles
 * 
 * Overrides mxShape to reset spacing.
 */
mxArrowConnector.prototype.resetStyles = function()
{
\tmxShape.prototype.resetStyles.apply(this, arguments);
\t
\tthis.arrowSpacing = mxConstants.ARROW_SPACING;
};

/**
 * Overrides apply to get smooth transition from default start- and endsize.
 */
mxArrowConnector.prototype.apply = function(state)
{
\tmxShape.prototype.apply.apply(this, arguments);

\tif (this.style != null)
\t{
\t\tthis.startSize = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.ARROW_SIZE / 5) * 3;
\t\tthis.endSize = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, mxConstants.ARROW_SIZE / 5) * 3;
\t}
};

/**
 * Function: augmentBoundingBox
 *
 * Augments the bounding box with the edge width and markers.
 */
mxArrowConnector.prototype.augmentBoundingBox = function(bbox)
{
\tmxShape.prototype.augmentBoundingBox.apply(this, arguments);
\t
\tvar w = this.getEdgeWidth();
\t
\tif (this.isMarkerStart())
\t{
\t\tw = Math.max(w, this.getStartArrowWidth());
\t}
\t
\tif (this.isMarkerEnd())
\t{
\t\tw = Math.max(w, this.getEndArrowWidth());
\t}
\t
\tbbox.grow((w / 2 + this.strokewidth) * this.scale);
};

/**
 * Function: paintEdgeShape
 * 
 * Paints the line shape.
 */
mxArrowConnector.prototype.paintEdgeShape = function(c, pts)
{
\t// Geometry of arrow
\tvar strokeWidth = this.strokewidth;
\t
\tif (this.outline)
\t{
\t\tstrokeWidth = Math.max(1, mxUtils.getNumber(this.style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth));
\t}
\t
\tvar startWidth = this.getStartArrowWidth() + strokeWidth;
\tvar endWidth = this.getEndArrowWidth() + strokeWidth;
\tvar edgeWidth = this.outline ? this.getEdgeWidth() + strokeWidth : this.getEdgeWidth();
\tvar openEnded = this.isOpenEnded();
\tvar markerStart = this.isMarkerStart();
\tvar markerEnd = this.isMarkerEnd();
\tvar spacing = (openEnded) ? 0 : this.arrowSpacing + strokeWidth / 2;
\tvar startSize = this.startSize + strokeWidth;
\tvar endSize = this.endSize + strokeWidth;
\tvar isRounded = this.isArrowRounded();
\t
\t// Base vector (between first points)
\tvar pe = pts[pts.length - 1];

\t// Finds first non-overlapping point
\tvar i0 = 1;
\t
\twhile (i0 < pts.length - 1 && pts[i0].x == pts[0].x && pts[i0].y == pts[0].y)
\t{
\t\ti0++;
\t}
\t
\tvar dx = pts[i0].x - pts[0].x;
\tvar dy = pts[i0].y - pts[0].y;
\tvar dist = Math.sqrt(dx * dx + dy * dy);
\t
\tif (dist == 0)
\t{
\t\treturn;
\t}
\t
\t// Computes the norm and the inverse norm
\tvar nx = dx / dist;
\tvar nx2, nx1 = nx;
\tvar ny = dy / dist;
\tvar ny2, ny1 = ny;
\tvar orthx = edgeWidth * ny;
\tvar orthy = -edgeWidth * nx;
\t
\t// Stores the inbound function calls in reverse order in fns
\tvar fns = [];
\t
\tif (isRounded)
\t{
\t\tc.setLineJoin('round');
\t}
\telse if (pts.length > 2)
\t{
\t\t// Only mitre if there are waypoints
\t\tc.setMiterLimit(1.42);
\t}

\tc.begin();

\tvar startNx = nx;
\tvar startNy = ny;

\tif (markerStart && !openEnded)
\t{
\t\tthis.paintMarker(c, pts[0].x, pts[0].y, nx, ny, startSize, startWidth, edgeWidth, spacing, true);
\t}
\telse
\t{
\t\tvar outStartX = pts[0].x + orthx / 2 + spacing * nx;
\t\tvar outStartY = pts[0].y + orthy / 2 + spacing * ny;
\t\tvar inEndX = pts[0].x - orthx / 2 + spacing * nx;
\t\tvar inEndY = pts[0].y - orthy / 2 + spacing * ny;
\t\t
\t\tif (openEnded)
\t\t{
\t\t\tc.moveTo(outStartX, outStartY);
\t\t\t
\t\t\tfns.push(function()
\t\t\t{
\t\t\t\tc.lineTo(inEndX, inEndY);
\t\t\t});
\t\t}
\t\telse
\t\t{
\t\t\tc.moveTo(inEndX, inEndY);
\t\t\tc.lineTo(outStartX, outStartY);
\t\t}
\t}
\t
\tvar dx1 = 0;
\tvar dy1 = 0;
\tvar dist1 = 0;

\tfor (var i = 0; i < pts.length - 2; i++)
\t{
\t\t// Work out in which direction the line is bending
\t\tvar 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);

\t\tdx1 = pts[i+2].x - pts[i+1].x;
\t\tdy1 = pts[i+2].y - pts[i+1].y;

\t\tdist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
\t\t
\t\tif (dist1 != 0)
\t\t{
\t\t\tnx1 = dx1 / dist1;
\t\t\tny1 = dy1 / dist1;
\t\t\t
\t\t\tvar tmp1 = nx * nx1 + ny * ny1;
\t\t\tvar tmp = Math.max(Math.sqrt((tmp1 + 1) / 2), 0.04);
\t\t\t
\t\t\t// Work out the normal orthogonal to the line through the control point and the edge sides intersection
\t\t\tnx2 = (nx + nx1);
\t\t\tny2 = (ny + ny1);
\t
\t\t\tvar dist2 = Math.sqrt(nx2 * nx2 + ny2 * ny2);
\t\t\t
\t\t\tif (dist2 != 0)
\t\t\t{
\t\t\t\tnx2 = nx2 / dist2;
\t\t\t\tny2 = ny2 / dist2;
\t\t\t\t
\t\t\t\t// Higher strokewidths require a larger minimum bend, 0.35 covers all but the most extreme cases
\t\t\t\tvar strokeWidthFactor = Math.max(tmp, Math.min(this.strokewidth / 200 + 0.04, 0.35));
\t\t\t\tvar angleFactor = (pos != 0 && isRounded) ? Math.max(0.1, strokeWidthFactor) : Math.max(tmp, 0.06);

\t\t\t\tvar outX = pts[i+1].x + ny2 * edgeWidth / 2 / angleFactor;
\t\t\t\tvar outY = pts[i+1].y - nx2 * edgeWidth / 2 / angleFactor;
\t\t\t\tvar inX = pts[i+1].x - ny2 * edgeWidth / 2 / angleFactor;
\t\t\t\tvar inY = pts[i+1].y + nx2 * edgeWidth / 2 / angleFactor;
\t\t\t\t
\t\t\t\tif (pos == 0 || !isRounded)
\t\t\t\t{
\t\t\t\t\t// If the two segments are aligned, or if we're not drawing curved sections between segments
\t\t\t\t\t// just draw straight to the intersection point
\t\t\t\t\tc.lineTo(outX, outY);
\t\t\t\t\t
\t\t\t\t\t(function(x, y)
\t\t\t\t\t{
\t\t\t\t\t\tfns.push(function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\tc.lineTo(x, y);
\t\t\t\t\t\t});
\t\t\t\t\t})(inX, inY);
\t\t\t\t}
\t\t\t\telse if (pos == -1)
\t\t\t\t{
\t\t\t\t\tvar c1x = inX + ny * edgeWidth;
\t\t\t\t\tvar c1y = inY - nx * edgeWidth;
\t\t\t\t\tvar c2x = inX + ny1 * edgeWidth;
\t\t\t\t\tvar c2y = inY - nx1 * edgeWidth;
\t\t\t\t\tc.lineTo(c1x, c1y);
\t\t\t\t\tc.quadTo(outX, outY, c2x, c2y);
\t\t\t\t\t
\t\t\t\t\t(function(x, y)
\t\t\t\t\t{
\t\t\t\t\t\tfns.push(function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\tc.lineTo(x, y);
\t\t\t\t\t\t});
\t\t\t\t\t})(inX, inY);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tc.lineTo(outX, outY);
\t\t\t\t\t
\t\t\t\t\t(function(x, y)
\t\t\t\t\t{
\t\t\t\t\t\tvar c1x = outX - ny * edgeWidth;
\t\t\t\t\t\tvar c1y = outY + nx * edgeWidth;
\t\t\t\t\t\tvar c2x = outX - ny1 * edgeWidth;
\t\t\t\t\t\tvar c2y = outY + nx1 * edgeWidth;
\t\t\t\t\t\t
\t\t\t\t\t\tfns.push(function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\tc.quadTo(x, y, c1x, c1y);
\t\t\t\t\t\t});
\t\t\t\t\t\tfns.push(function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\tc.lineTo(c2x, c2y);
\t\t\t\t\t\t});
\t\t\t\t\t})(inX, inY);
\t\t\t\t}
\t\t\t\t
\t\t\t\tnx = nx1;
\t\t\t\tny = ny1;
\t\t\t}
\t\t}
\t}
\t
\torthx = edgeWidth * ny1;
\torthy = - edgeWidth * nx1;

\tif (markerEnd && !openEnded)
\t{
\t\tthis.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, false);
\t}
\telse
\t{
\t\tc.lineTo(pe.x - spacing * nx1 + orthx / 2, pe.y - spacing * ny1 + orthy / 2);
\t\t
\t\tvar inStartX = pe.x - spacing * nx1 - orthx / 2;
\t\tvar inStartY = pe.y - spacing * ny1 - orthy / 2;

\t\tif (!openEnded)
\t\t{
\t\t\tc.lineTo(inStartX, inStartY);
\t\t}
\t\telse
\t\t{
\t\t\tc.moveTo(inStartX, inStartY);
\t\t\t
\t\t\tfns.splice(0, 0, function()
\t\t\t{
\t\t\t\tc.moveTo(inStartX, inStartY);
\t\t\t});
\t\t}
\t}
\t
\tfor (var i = fns.length - 1; i >= 0; i--)
\t{
\t\tfns[i]();
\t}

\tif (openEnded)
\t{
\t\tc.end();
\t\tc.stroke();
\t}
\telse
\t{
\t\tc.close();
\t\tc.fillAndStroke();
\t}
\t
\t// Workaround for shadow on top of base arrow
\tc.setShadow(false);
\t
\t// Need to redraw the markers without the low miter limit
\tc.setMiterLimit(4);
\t
\tif (isRounded)
\t{
\t\tc.setLineJoin('flat');
\t}

\tif (pts.length > 2)
\t{
\t\t// Only to repaint markers if no waypoints
\t\t// Need to redraw the markers without the low miter limit
\t\tc.setMiterLimit(4);
\t\tif (markerStart && !openEnded)
\t\t{
\t\t\tc.begin();
\t\t\tthis.paintMarker(c, pts[0].x, pts[0].y, startNx, startNy, startSize, startWidth, edgeWidth, spacing, true);
\t\t\tc.stroke();
\t\t\tc.end();
\t\t}
\t\t
\t\tif (markerEnd && !openEnded)
\t\t{
\t\t\tc.begin();
\t\t\tthis.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, true);
\t\t\tc.stroke();
\t\t\tc.end();
\t\t}
\t}
};

/**
 * Function: paintMarker
 * 
 * Paints the marker.
 */
mxArrowConnector.prototype.paintMarker = function(c, ptX, ptY, nx, ny, size, arrowWidth, edgeWidth, spacing, initialMove)
{
\tvar widthArrowRatio = edgeWidth / arrowWidth;
\tvar orthx = edgeWidth * ny / 2;
\tvar orthy = -edgeWidth * nx / 2;

\tvar spaceX = (spacing + size) * nx;
\tvar spaceY = (spacing + size) * ny;

\tif (initialMove)
\t{
\t\tc.moveTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
\t}
\telse
\t{
\t\tc.lineTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
\t}

\tc.lineTo(ptX - orthx / widthArrowRatio + spaceX, ptY - orthy / widthArrowRatio + spaceY);
\tc.lineTo(ptX + spacing * nx, ptY + spacing * ny);
\tc.lineTo(ptX + orthx / widthArrowRatio + spaceX, ptY + orthy / widthArrowRatio + spaceY);
\tc.lineTo(ptX + orthx + spaceX, ptY + orthy + spaceY);
}

/**
 * Function: isArrowRounded
 * 
 * Returns wether the arrow is rounded
 */
mxArrowConnector.prototype.isArrowRounded = function()
{
\treturn this.isRounded;
};

/**
 * Function: getStartArrowWidth
 * 
 * Returns the width of the start arrow
 */
mxArrowConnector.prototype.getStartArrowWidth = function()
{
\treturn mxConstants.ARROW_WIDTH;
};

/**
 * Function: getEndArrowWidth
 * 
 * Returns the width of the end arrow
 */
mxArrowConnector.prototype.getEndArrowWidth = function()
{
\treturn mxConstants.ARROW_WIDTH;
};

/**
 * Function: getEdgeWidth
 * 
 * Returns the width of the body of the edge
 */
mxArrowConnector.prototype.getEdgeWidth = function()
{
\treturn mxConstants.ARROW_WIDTH / 3;
};

/**
 * Function: isOpenEnded
 * 
 * Returns whether the ends of the shape are drawn
 */
mxArrowConnector.prototype.isOpenEnded = function()
{
\treturn false;
};

/**
 * Function: isMarkerStart
 * 
 * Returns whether the start marker is drawn
 */
mxArrowConnector.prototype.isMarkerStart = function()
{
\treturn (mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, mxConstants.NONE) != mxConstants.NONE);
};

/**
 * Function: isMarkerEnd
 * 
 * Returns whether the end marker is drawn
 */
mxArrowConnector.prototype.isMarkerEnd = function()
{
\treturn (mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, mxConstants.NONE) != mxConstants.NONE);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxText
 *
 * Extends <mxShape> to implement a text shape. To change vertical text from
 * bottom to top to top to bottom, the following code can be used:
 * 
 * (code)
 * mxText.prototype.verticalTextRotation = 90;
 * (end)
 * 
 * Constructor: mxText
 *
 * Constructs a new text shape.
 * 
 * Parameters:
 * 
 * value - String that represents the text to be displayed. This is stored in
 * <value>.
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * align - Specifies the horizontal alignment. Default is ''. This is stored in
 * <align>.
 * valign - Specifies the vertical alignment. Default is ''. This is stored in
 * <valign>.
 * color - String that specifies the text color. Default is 'black'. This is
 * stored in <color>.
 * family - String that specifies the font family. Default is
 * <mxConstants.DEFAULT_FONTFAMILY>. This is stored in <family>.
 * size - Integer that specifies the font size. Default is
 * <mxConstants.DEFAULT_FONTSIZE>. This is stored in <size>.
 * fontStyle - Specifies the font style. Default is 0. This is stored in
 * <fontStyle>.
 * spacing - Integer that specifies the global spacing. Default is 2. This is
 * stored in <spacing>.
 * spacingTop - Integer that specifies the top spacing. Default is 0. The
 * sum of the spacing and this is stored in <spacingTop>.
 * spacingRight - Integer that specifies the right spacing. Default is 0. The
 * sum of the spacing and this is stored in <spacingRight>.
 * spacingBottom - Integer that specifies the bottom spacing. Default is 0.The
 * sum of the spacing and this is stored in <spacingBottom>.
 * spacingLeft - Integer that specifies the left spacing. Default is 0. The
 * sum of the spacing and this is stored in <spacingLeft>.
 * horizontal - Boolean that specifies if the label is horizontal. Default is
 * true. This is stored in <horizontal>.
 * background - String that specifies the background color. Default is null.
 * This is stored in <background>.
 * border - String that specifies the label border color. Default is null.
 * This is stored in <border>.
 * wrap - Specifies if word-wrapping should be enabled. Default is false.
 * This is stored in <wrap>.
 * clipped - Specifies if the label should be clipped. Default is false.
 * This is stored in <clipped>.
 * overflow - Value of the overflow style. Default is 'visible'.
 */
function mxText(value, bounds, align, valign, color,
\tfamily,\tsize, fontStyle, spacing, spacingTop, spacingRight,
\tspacingBottom, spacingLeft, horizontal, background, border,
\twrap, clipped, overflow, labelPadding, textDirection)
{
\tmxShape.call(this);
\tthis.value = value;
\tthis.bounds = bounds;
\tthis.color = (color != null) ? color : 'black';
\tthis.align = (align != null) ? align : mxConstants.ALIGN_CENTER;
\tthis.valign = (valign != null) ? valign : mxConstants.ALIGN_MIDDLE;
\tthis.family = (family != null) ? family : mxConstants.DEFAULT_FONTFAMILY;
\tthis.size = (size != null) ? size : mxConstants.DEFAULT_FONTSIZE;
\tthis.fontStyle = (fontStyle != null) ? fontStyle : mxConstants.DEFAULT_FONTSTYLE;
\tthis.spacing = parseInt(spacing || 2);
\tthis.spacingTop = this.spacing + parseInt(spacingTop || 0);
\tthis.spacingRight = this.spacing + parseInt(spacingRight || 0);
\tthis.spacingBottom = this.spacing + parseInt(spacingBottom || 0);
\tthis.spacingLeft = this.spacing + parseInt(spacingLeft || 0);
\tthis.horizontal = (horizontal != null) ? horizontal : true;
\tthis.background = background;
\tthis.border = border;
\tthis.wrap = (wrap != null) ? wrap : false;
\tthis.clipped = (clipped != null) ? clipped : false;
\tthis.overflow = (overflow != null) ? overflow : 'visible';
\tthis.labelPadding = (labelPadding != null) ? labelPadding : 0;
\tthis.textDirection = textDirection;
\tthis.rotation = 0;
\tthis.updateMargin();
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxText, mxShape);

/**
 * Variable: baseSpacingTop
 * 
 * Specifies the spacing to be added to the top spacing. Default is 0. Use the
 * value 5 here to get the same label positions as in mxGraph 1.x.
 */
mxText.prototype.baseSpacingTop = 0;

/**
 * Variable: baseSpacingBottom
 * 
 * Specifies the spacing to be added to the bottom spacing. Default is 0. Use the
 * value 1 here to get the same label positions as in mxGraph 1.x.
 */
mxText.prototype.baseSpacingBottom = 0;

/**
 * Variable: baseSpacingLeft
 * 
 * Specifies the spacing to be added to the left spacing. Default is 0.
 */
mxText.prototype.baseSpacingLeft = 0;

/**
 * Variable: baseSpacingRight
 * 
 * Specifies the spacing to be added to the right spacing. Default is 0.
 */
mxText.prototype.baseSpacingRight = 0;

/**
 * Variable: replaceLinefeeds
 * 
 * Specifies if linefeeds in HTML labels should be replaced with BR tags.
 * Default is true.
 */
mxText.prototype.replaceLinefeeds = true;

/**
 * Variable: verticalTextRotation
 * 
 * Rotation for vertical text. Default is -90 (bottom to top).
 */
mxText.prototype.verticalTextRotation = -90;

/**
 * Variable: ignoreClippedStringSize
 * 
 * Specifies if the string size should be measured in <updateBoundingBox> if
 * the label is clipped and the label position is center and middle. If this is
 * true, then the bounding box will be set to <bounds>. Default is true.
 * <ignoreStringSize> has precedence over this switch.
 */
mxText.prototype.ignoreClippedStringSize = true;

/**
 * Variable: ignoreStringSize
 * 
 * Specifies if the actual string size should be measured. If disabled the
 * boundingBox will not ignore the actual size of the string, otherwise
 * <bounds> will be used instead. Default is false.
 */
mxText.prototype.ignoreStringSize = false;

/**
 * Variable: textWidthPadding
 * 
 * Specifies the padding to be added to the text width for the bounding box.
 * This is needed to make sure no clipping is applied to borders. Default is 4
 * for IE 8 standards mode and 3 for all others.
 */
mxText.prototype.textWidthPadding = (document.documentMode == 8 && !mxClient.IS_EM) ? 4 : 3;

/**
 * Variable: lastValue
 * 
 * Contains the last rendered text value. Used for caching.
 */
mxText.prototype.lastValue = null;

/**
 * Variable: cacheEnabled
 * 
 * Specifies if caching for HTML labels should be enabled. Default is true.
 */
mxText.prototype.cacheEnabled = true;

/**
 * Function: isParseVml
 * 
 * Text shapes do not contain VML markup and do not need to be parsed. This
 * method returns false to speed up rendering in IE8.
 */
mxText.prototype.isParseVml = function()
{
\treturn false;
};

/**
 * Function: isHtmlAllowed
 * 
 * Returns true if HTML is allowed for this shape. This implementation returns
 * true if the browser is not in IE8 standards mode.
 */
mxText.prototype.isHtmlAllowed = function()
{
\treturn document.documentMode != 8 || mxClient.IS_EM;
};

/**
 * Function: getSvgScreenOffset
 * 
 * Disables offset in IE9 for crisper image output.
 */
mxText.prototype.getSvgScreenOffset = function()
{
\treturn 0;
};

/**
 * Function: checkBounds
 * 
 * Returns true if the bounds are not null and all of its variables are numeric.
 */
mxText.prototype.checkBounds = function()
{
\treturn (!isNaN(this.scale) && isFinite(this.scale) && this.scale > 0 &&
\t\t\tthis.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
\t\t\t!isNaN(this.bounds.width) && !isNaN(this.bounds.height));
};

/**
 * Function: paint
 * 
 * Generic rendering code.
 */
mxText.prototype.paint = function(c, update)
{
\t// Scale is passed-through to canvas
\tvar s = this.scale;
\tvar x = this.bounds.x / s;
\tvar y = this.bounds.y / s;
\tvar w = this.bounds.width / s;
\tvar h = this.bounds.height / s;
\t
\tthis.updateTransform(c, x, y, w, h);
\tthis.configureCanvas(c, x, y, w, h);
\t
\tif (update)
\t{
\t\tc.updateText(x, y, w, h, this.align, this.valign, this.wrap, this.overflow,
\t\t\t\tthis.clipped, this.getTextRotation(), this.node);
\t}
\telse
\t{
\t\t// Checks if text contains HTML markup
\t\tvar realHtml = mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML;
\t\t
\t\t// Always renders labels as HTML in VML
\t\tvar fmt = (realHtml || c instanceof mxVmlCanvas2D) ? 'html' : '';
\t\tvar val = this.value;
\t\t
\t\tif (!realHtml && fmt == 'html')
\t\t{
\t\t\tval = mxUtils.htmlEntities(val, false);
\t\t}
\t\t
\t\tif (fmt == 'html' && !mxUtils.isNode(this.value))
\t\t{
\t\t\tval = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');\t\t\t
\t\t}
\t\t
\t\t// Handles trailing newlines to make sure they are visible in rendering output
\t\tval = (!mxUtils.isNode(this.value) && this.replaceLinefeeds && fmt == 'html') ?
\t\t\tval.replace(/\\n/g, '<br/>') : val;
\t\t\t
\t\tvar dir = this.textDirection;
\t
\t\tif (dir == mxConstants.TEXT_DIRECTION_AUTO && !realHtml)
\t\t{
\t\t\tdir = this.getAutoDirection();
\t\t}
\t\t
\t\tif (dir != mxConstants.TEXT_DIRECTION_LTR && dir != mxConstants.TEXT_DIRECTION_RTL)
\t\t{
\t\t\tdir = null;
\t\t}
\t\t
\t\tc.text(x, y, w, h, val, this.align, this.valign, this.wrap, fmt,
\t\t\tthis.overflow, this.clipped, this.getTextRotation(), dir);
\t}
};

/**
 * Function: redraw
 * 
 * Renders the text using the given DOM nodes.
 */
mxText.prototype.redraw = function()
{
\tif (this.visible && this.checkBounds() && this.cacheEnabled && this.lastValue == this.value &&
\t\t(mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML))
\t{
\t\tif (this.node.nodeName == 'DIV' && (this.isHtmlAllowed() || !mxClient.IS_VML))
\t\t{
\t\t\tif (mxClient.IS_SVG)
\t\t\t{
\t\t\t\tthis.redrawHtmlShapeWithCss3();\t
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.updateSize(this.node, (this.state == null || this.state.view.textDiv == null));
\t
\t\t\t\tif (mxClient.IS_IE && (document.documentMode == null || document.documentMode <= 8))
\t\t\t\t{
\t\t\t\t\tthis.updateHtmlFilter();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.updateHtmlTransform();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.updateBoundingBox();
\t\t}
\t\telse
\t\t{
\t\t\tvar canvas = this.createCanvas();

\t\t\tif (canvas != null && canvas.updateText != null)
\t\t\t{
\t\t\t\t// Specifies if events should be handled
\t\t\t\tcanvas.pointerEvents = this.pointerEvents;
\t
\t\t\t\tthis.paint(canvas, true);
\t\t\t\tthis.destroyCanvas(canvas);
\t\t\t\tthis.updateBoundingBox();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Fallback if canvas does not support updateText (VML)
\t\t\t\tmxShape.prototype.redraw.apply(this, arguments);
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tmxShape.prototype.redraw.apply(this, arguments);
\t\t
\t\tif (mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML)
\t\t{
\t\t\tthis.lastValue = this.value;
\t\t}
\t\telse
\t\t{
\t\t\tthis.lastValue = null;
\t\t}
\t}
};

/**
 * Function: resetStyles
 * 
 * Resets all styles.
 */
mxText.prototype.resetStyles = function()
{
\tmxShape.prototype.resetStyles.apply(this, arguments);
\t
\tthis.color = 'black';
\tthis.align = mxConstants.ALIGN_CENTER;
\tthis.valign = mxConstants.ALIGN_MIDDLE;
\tthis.family = mxConstants.DEFAULT_FONTFAMILY;
\tthis.size = mxConstants.DEFAULT_FONTSIZE;
\tthis.fontStyle = mxConstants.DEFAULT_FONTSTYLE;
\tthis.spacing = 2;
\tthis.spacingTop = 2;
\tthis.spacingRight = 2;
\tthis.spacingBottom = 2;
\tthis.spacingLeft = 2;
\tthis.horizontal = true;
\tdelete this.background;
\tdelete this.border;
\tthis.textDirection = mxConstants.DEFAULT_TEXT_DIRECTION;
\tdelete this.margin;
};

/**
 * Function: apply
 * 
 * Extends mxShape to update the text styles.
 *
 * Parameters:
 *
 * state - <mxCellState> of the corresponding cell.
 */
mxText.prototype.apply = function(state)
{
\tvar old = this.spacing;
\tmxShape.prototype.apply.apply(this, arguments);
\t
\tif (this.style != null)
\t{
\t\tthis.fontStyle = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSTYLE, this.fontStyle);
\t\tthis.family = mxUtils.getValue(this.style, mxConstants.STYLE_FONTFAMILY, this.family);
\t\tthis.size = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, this.size);
\t\tthis.color = mxUtils.getValue(this.style, mxConstants.STYLE_FONTCOLOR, this.color);
\t\tthis.align = mxUtils.getValue(this.style, mxConstants.STYLE_ALIGN, this.align);
\t\tthis.valign = mxUtils.getValue(this.style, mxConstants.STYLE_VERTICAL_ALIGN, this.valign);
\t\tthis.spacing = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING, this.spacing));
\t\tthis.spacingTop = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_TOP, this.spacingTop - old)) + this.spacing;
\t\tthis.spacingRight = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_RIGHT, this.spacingRight - old)) + this.spacing;
\t\tthis.spacingBottom = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_BOTTOM, this.spacingBottom - old)) + this.spacing;
\t\tthis.spacingLeft = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_LEFT, this.spacingLeft - old)) + this.spacing;
\t\tthis.horizontal = mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, this.horizontal);
\t\tthis.background = mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, this.background);
\t\tthis.border = mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_BORDERCOLOR, this.border);
\t\tthis.textDirection = mxUtils.getValue(this.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
\t\tthis.opacity = mxUtils.getValue(this.style, mxConstants.STYLE_TEXT_OPACITY, 100);
\t\tthis.updateMargin();
\t}
\t
\tthis.flipV = null;
\tthis.flipH = null;
};

/**
 * Function: getAutoDirection
 * 
 * Used to determine the automatic text direction. Returns
 * <mxConstants.TEXT_DIRECTION_LTR> or <mxConstants.TEXT_DIRECTION_RTL>
 * depending on the contents of <value>. This is not invoked for HTML, wrapped
 * content or if <value> is a DOM node.
 */
mxText.prototype.getAutoDirection = function()
{
\t// Looks for strong (directional) characters
\tvar tmp = /[A-Za-z\\u05d0-\\u065f\\u066a-\\u06ef\\u06fa-\\u07ff\\ufb1d-\\ufdff\\ufe70-\\ufefc]/.exec(this.value);
\t
\t// Returns the direction defined by the character
\treturn (tmp != null && tmp.length > 0 && tmp[0] > 'z') ?
\t\tmxConstants.TEXT_DIRECTION_RTL : mxConstants.TEXT_DIRECTION_LTR;
};

/**
 * Function: getContentNode
 * 
 * Returns the node that contains the rendered input.
 */
mxText.prototype.getContentNode = function()
{
\tvar result = this.node;
\t
\tif (result != null)
\t{
\t\t// Rendered with no foreignObject
\t\tif (result.ownerSVGElement == null)
\t\t{
\t\t\tresult = this.node.firstChild.firstChild;
\t\t}
\t\telse
\t\t{
\t\t\t// Innermost DIV that contains the actual content
\t\t\tresult = result.firstChild.firstChild.firstChild.firstChild.firstChild;
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: updateBoundingBox
 *
 * Updates the <boundingBox> for this shape using the given node and position.
 */
mxText.prototype.updateBoundingBox = function()
{
\tvar node = this.node;
\tthis.boundingBox = this.bounds.clone();
\tvar rot = this.getTextRotation();
\t
\tvar h = (this.style != null) ? mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER) : null;
\tvar v = (this.style != null) ? mxUtils.getValue(this.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE) : null;

\tif (!this.ignoreStringSize && node != null && this.overflow != 'fill' && (!this.clipped ||
\t\t!this.ignoreClippedStringSize || h != mxConstants.ALIGN_CENTER || v != mxConstants.ALIGN_MIDDLE))
\t{
\t\tvar ow = null;
\t\tvar oh = null;
\t\t
\t\tif (node.ownerSVGElement != null)
\t\t{
\t\t\tif (node.firstChild != null && node.firstChild.firstChild != null &&
\t\t\t\tnode.firstChild.firstChild.nodeName == 'foreignObject')
\t\t\t{
\t\t\t\t// Uses second inner DIV for font metrics
\t\t\t\tnode = node.firstChild.firstChild.firstChild.firstChild;
\t\t\t\toh = node.offsetHeight * this.scale;
\t\t\t\t
\t\t\t\tif (this.overflow == 'width')
\t\t\t\t{
\t\t\t\t\tow = this.boundingBox.width;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tow = node.offsetWidth * this.scale;\t
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\tvar b = node.getBBox();
\t\t\t\t\t
\t\t\t\t\t// Workaround for bounding box of empty string
\t\t\t\t\tif (typeof(this.value) == 'string' && mxUtils.trim(this.value) == 0)
\t\t\t\t\t{
\t\t\t\t\t\tthis.boundingBox = null;
\t\t\t\t\t}
\t\t\t\t\telse if (b.width == 0 && b.height == 0)
\t\t\t\t\t{
\t\t\t\t\t\tthis.boundingBox = null;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tthis.boundingBox = new mxRectangle(b.x, b.y, b.width, b.height);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tcatch (e)
\t\t\t\t{
\t\t\t\t\t// Ignores NS_ERROR_FAILURE in FF if container display is none.
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar td = (this.state != null) ? this.state.view.textDiv : null;

\t\t\t// Use cached offset size
\t\t\tif (this.offsetWidth != null && this.offsetHeight != null)
\t\t\t{
\t\t\t\tow = this.offsetWidth * this.scale;
\t\t\t\toh = this.offsetHeight * this.scale;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Cannot get node size while container hidden so a
\t\t\t\t// shared temporary DIV is used for text measuring
\t\t\t\tif (td != null)
\t\t\t\t{
\t\t\t\t\tthis.updateFont(td);
\t\t\t\t\tthis.updateSize(td, false);
\t\t\t\t\tthis.updateInnerHtml(td);

\t\t\t\t\tnode = td;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar sizeDiv = node;

\t\t\t\tif (document.documentMode == 8 && !mxClient.IS_EM)
\t\t\t\t{
\t\t\t\t\tvar w = Math.round(this.bounds.width / this.scale);
\t
\t\t\t\t\tif (this.wrap && w > 0)
\t\t\t\t\t{
\t\t\t\t\t\tnode.style.wordWrap = mxConstants.WORD_WRAP;
\t\t\t\t\t\tnode.style.whiteSpace = 'normal';

\t\t\t\t\t\tif (node.style.wordWrap != 'break-word')
\t\t\t\t\t\t{
\t\t\t\t\t\t\t// Innermost DIV is used for measuring text
\t\t\t\t\t\t\tvar divs = sizeDiv.getElementsByTagName('div');
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (divs.length > 0)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tsizeDiv = divs[divs.length - 1];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tow = sizeDiv.offsetWidth + 2;
\t\t\t\t\t\t\tdivs = this.node.getElementsByTagName('div');
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (this.clipped)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tow = Math.min(w, ow);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Second last DIV width must be updated in DOM tree
\t\t\t\t\t\t\tif (divs.length > 1)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tdivs[divs.length - 2].style.width = ow + 'px';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tnode.style.whiteSpace = 'nowrap';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
\t\t\t\t{
\t\t\t\t\tsizeDiv = sizeDiv.firstChild;
\t\t\t\t}

\t\t\t\tthis.offsetWidth = sizeDiv.offsetWidth + this.textWidthPadding;
\t\t\t\tthis.offsetHeight = sizeDiv.offsetHeight;
\t\t\t\t
\t\t\t\tow = this.offsetWidth * this.scale;
\t\t\t\toh = this.offsetHeight * this.scale;
\t\t\t}
\t\t}

\t\tif (ow != null && oh != null)
\t\t{\t
\t\t\tthis.boundingBox = new mxRectangle(this.bounds.x,
\t\t\t\tthis.bounds.y, ow, oh);
\t\t}
\t}

\tif (this.boundingBox != null)
\t{
\t\tif (rot != 0)
\t\t{
\t\t\t// Accounts for pre-rotated x and y
\t\t\tvar bbox = mxUtils.getBoundingBox(new mxRectangle(
\t\t\t\tthis.margin.x * this.boundingBox.width,
\t\t\t\tthis.margin.y * this.boundingBox.height,
\t\t\t\tthis.boundingBox.width, this.boundingBox.height),
\t\t\t\trot, new mxPoint(0, 0));
\t\t\t
\t\t\tthis.unrotatedBoundingBox = mxRectangle.fromRectangle(this.boundingBox);
\t\t\tthis.unrotatedBoundingBox.x += this.margin.x * this.unrotatedBoundingBox.width;
\t\t\tthis.unrotatedBoundingBox.y += this.margin.y * this.unrotatedBoundingBox.height;
\t\t\t
\t\t\tthis.boundingBox.x += bbox.x;
\t\t\tthis.boundingBox.y += bbox.y;
\t\t\tthis.boundingBox.width = bbox.width;
\t\t\tthis.boundingBox.height = bbox.height;
\t\t}
\t\telse
\t\t{
\t\t\tthis.boundingBox.x += this.margin.x * this.boundingBox.width;
\t\t\tthis.boundingBox.y += this.margin.y * this.boundingBox.height;
\t\t\tthis.unrotatedBoundingBox = null;
\t\t}
\t}
};

/**
 * Function: getShapeRotation
 * 
 * Returns 0 to avoid using rotation in the canvas via updateTransform.
 */
mxText.prototype.getShapeRotation = function()
{
\treturn 0;
};

/**
 * Function: getTextRotation
 * 
 * Returns the rotation for the text label of the corresponding shape.
 */
mxText.prototype.getTextRotation = function()
{
\treturn (this.state != null && this.state.shape != null) ? this.state.shape.getTextRotation() : 0;
};

/**
 * Function: isPaintBoundsInverted
 * 
 * Inverts the bounds if <mxShape.isBoundsInverted> returns true or if the
 * horizontal style is false.
 */
mxText.prototype.isPaintBoundsInverted = function()
{
\treturn !this.horizontal && this.state != null && this.state.view.graph.model.isVertex(this.state.cell);
};

/**
 * Function: configureCanvas
 * 
 * Sets the state of the canvas for drawing the shape.
 */
mxText.prototype.configureCanvas = function(c, x, y, w, h)
{
\tmxShape.prototype.configureCanvas.apply(this, arguments);
\t
\tc.setFontColor(this.color);
\tc.setFontBackgroundColor(this.background);
\tc.setFontBorderColor(this.border);
\tc.setFontFamily(this.family);
\tc.setFontSize(this.size);
\tc.setFontStyle(this.fontStyle);
};

/**
 * Function: updateVmlContainer
 * 
 * Sets the width and height of the container to 1px.
 */
mxText.prototype.updateVmlContainer = function()
{
\tthis.node.style.left = Math.round(this.bounds.x) + 'px';
\tthis.node.style.top = Math.round(this.bounds.y) + 'px';
\tthis.node.style.width = '1px';
\tthis.node.style.height = '1px';
\tthis.node.style.overflow = 'visible';
};

/**
 * Function: getHtmlValue
 * 
 * Private helper function to create SVG elements
 */
mxText.prototype.getHtmlValue = function()
{
\tvar val = this.value;
\t
\tif (this.dialect != mxConstants.DIALECT_STRICTHTML)
\t{
\t\tval = mxUtils.htmlEntities(val, false);
\t}
\t
\t// Handles trailing newlines to make sure they are visible in rendering output
\tval = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');
\tval = (this.replaceLinefeeds) ? val.replace(/\\n/g, '<br/>') : val;
\t
\treturn val;
};

/**
 * Function: getTextCss
 * 
 * Private helper function to create SVG elements
 */
mxText.prototype.getTextCss = function()
{
\tvar lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' :
\t\tmxConstants.LINE_HEIGHT;

\tvar css = 'display: inline-block; font-size: ' + this.size + 'px; ' +
\t\t'font-family: ' + this.family + '; color: ' + this.color + '; line-height: ' + lh +
\t\t'; pointer-events: ' + ((this.pointerEvents) ? 'all' : 'none') + '; ';

\tif ((this.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\tcss += 'font-weight: bold; ';
\t}

\tif ((this.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\tcss += 'font-style: italic; ';
\t}
\t
\tvar deco = [];
\t
\tif ((this.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\tdeco.push('underline');
\t}
\t
\tif ((this.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t{
\t\tdeco.push('line-through');
\t}
\t
\tif (deco.length > 0)
\t{
\t\tcss += 'text-decoration: ' + deco.join(' ') + '; ';
\t}

\treturn css;
};

/**
 * Function: redrawHtmlShape
 *
 * Updates the HTML node(s) to reflect the latest bounds and scale.
 */
mxText.prototype.redrawHtmlShape = function()
{
\tif (mxClient.IS_SVG)
\t{
\t\tthis.redrawHtmlShapeWithCss3();\t
\t}
\telse
\t{
\t\tvar style = this.node.style;
\t
\t\t// Resets CSS styles
\t\tstyle.whiteSpace = 'normal';
\t\tstyle.overflow = '';
\t\tstyle.width = '';
\t\tstyle.height = '';
\t\t
\t\tthis.updateValue();
\t\tthis.updateFont(this.node);
\t\tthis.updateSize(this.node, (this.state == null || this.state.view.textDiv == null));
\t\t
\t\tthis.offsetWidth = null;
\t\tthis.offsetHeight = null;
\t
\t\tif (mxClient.IS_IE && (document.documentMode == null || document.documentMode <= 8))
\t\t{
\t\t\tthis.updateHtmlFilter();
\t\t}
\t\telse
\t\t{
\t\t\tthis.updateHtmlTransform();
\t\t}
\t}
};

/**
 * Function: redrawHtmlShapeWithCss3
 *
 * Updates the HTML node(s) to reflect the latest bounds and scale.
 */
mxText.prototype.redrawHtmlShapeWithCss3 = function()
{
\tvar w = Math.max(0, Math.round(this.bounds.width / this.scale));
\tvar h = Math.max(0, Math.round(this.bounds.height / this.scale));
\tvar flex = 'position: absolute; left: ' + Math.round(this.bounds.x) + 'px; ' +
\t\t'top: ' + Math.round(this.bounds.y) + 'px; pointer-events: none; ';
\tvar block = this.getTextCss();
\t
\tmxSvgCanvas2D.createCss(w + 2, h, this.align, this.valign, this.wrap, this.overflow, this.clipped,
\t\t(this.background != null) ? mxUtils.htmlEntities(this.background) : null,
\t\t(this.border != null) ? mxUtils.htmlEntities(this.border) : null,
\t\tflex, block, this.scale, mxUtils.bind(this, function(dx, dy, flex, item, block, ofl)
\t{
\t\tvar r = this.getTextRotation();
\t\tvar tr = ((this.scale != 1) ? 'scale(' + this.scale + ') ' : '') +
\t\t\t((r != 0) ? 'rotate(' + r + 'deg) ' : '') +
\t\t\t((this.margin.x != 0 || this.margin.y != 0) ?
\t\t\t\t'translate(' + (this.margin.x * 100) + '%,' +
\t\t\t\t\t(this.margin.y * 100) + '%)' : '');
\t\t
\t\tif (tr != '')
\t\t{
\t\t\ttr = 'transform-origin: 0 0; transform: ' + tr + '; ';
\t\t}

\t\tif (ofl == '')
\t\t{
\t\t\tflex += item;
\t\t\titem = 'display:inline-block; min-width: 100%; ' + tr;
\t\t}
\t\telse
\t\t{
\t\t\titem += tr;
\t\t\t
\t\t\tif (mxClient.IS_SF)
\t\t\t{
\t\t\t\titem += '-webkit-clip-path: content-box;';
\t\t\t}
\t\t}

\t\tif (this.opacity < 100)
\t\t{
\t\t\tblock += 'opacity: ' + (this.opacity / 100) + '; ';
\t\t}
\t\t
\t\tthis.node.setAttribute('style', flex);
\t\t
\t\tvar html = (mxUtils.isNode(this.value)) ? this.value.outerHTML : this.getHtmlValue();
\t\t
\t\tif (this.node.firstChild == null)
\t\t{
\t\t\tthis.node.innerHTML = '<div><div>' + html +'</div></div>';
\t\t}

\t\tthis.node.firstChild.firstChild.setAttribute('style', block);
\t\tthis.node.firstChild.setAttribute('style', item);
\t}));
};

/**
 * Function: updateHtmlTransform
 *
 * Returns the spacing as an <mxPoint>.
 */
mxText.prototype.updateHtmlTransform = function()
{
\tvar theta = this.getTextRotation();
\tvar style = this.node.style;
\tvar dx = this.margin.x;
\tvar dy = this.margin.y;
\t
\tif (theta != 0)
\t{
\t\tmxUtils.setPrefixedStyle(style, 'transformOrigin', (-dx * 100) + '%' + ' ' + (-dy * 100) + '%');
\t\tmxUtils.setPrefixedStyle(style, 'transform', 'translate(' + (dx * 100) + '%' + ',' + (dy * 100) + '%) ' +
\t\t\t'scale(' + this.scale + ') rotate(' + theta + 'deg)');
\t}
\telse
\t{
\t\tmxUtils.setPrefixedStyle(style, 'transformOrigin', '0% 0%');
\t\tmxUtils.setPrefixedStyle(style, 'transform', 'scale(' + this.scale + ') ' +
\t\t\t'translate(' + (dx * 100) + '%' + ',' + (dy * 100) + '%)');
\t}

\tstyle.left = Math.round(this.bounds.x - Math.ceil(dx * ((this.overflow != 'fill' &&
\t\tthis.overflow != 'width') ? 3 : 1))) + 'px';
\tstyle.top = Math.round(this.bounds.y - dy * ((this.overflow != 'fill') ? 3 : 1)) + 'px';
\t
\tif (this.opacity < 100)
\t{
\t\tstyle.opacity = this.opacity / 100;
\t}
\telse
\t{
\t\tstyle.opacity = '';
\t}
};

/**
 * Function: updateInnerHtml
 * 
 * Sets the inner HTML of the given element to the <value>.
 */
mxText.prototype.updateInnerHtml = function(elt)
{
\tif (mxUtils.isNode(this.value))
\t{
\t\telt.innerHTML = this.value.outerHTML;
\t}
\telse
\t{
\t\tvar val = this.value;
\t\t
\t\tif (this.dialect != mxConstants.DIALECT_STRICTHTML)
\t\t{
\t\t\t// LATER: Can be cached in updateValue
\t\t\tval = mxUtils.htmlEntities(val, false);
\t\t}
\t\t
\t\t// Handles trailing newlines to make sure they are visible in rendering output
\t\tval = mxUtils.replaceTrailingNewlines(val, '<div>&nbsp;</div>');
\t\tval = (this.replaceLinefeeds) ? val.replace(/\\n/g, '<br/>') : val;
\t\tval = '<div style=\"display:inline-block;_display:inline;\">' + val + '</div>';
\t\t
\t\telt.innerHTML = val;
\t}
};

/**
 * Function: updateHtmlFilter
 *
 * Rotated text rendering quality is bad for IE9 quirks/IE8 standards
 */
mxText.prototype.updateHtmlFilter = function()
{
\tvar style = this.node.style;
\tvar dx = this.margin.x;
\tvar dy = this.margin.y;
\tvar s = this.scale;
\t
\t// Resets filter before getting offsetWidth
\tmxUtils.setOpacity(this.node, this.opacity);
\t
\t// Adds 1 to match table height in 1.x
\tvar ow = 0;
\tvar oh = 0;
\tvar td = (this.state != null) ? this.state.view.textDiv : null;
\tvar sizeDiv = this.node;
\t
\t// Fallback for hidden text rendering in IE quirks mode
\tif (td != null)
\t{
\t\ttd.style.overflow = '';
\t\ttd.style.height = '';
\t\ttd.style.width = '';
\t\t
\t\tthis.updateFont(td);
\t\tthis.updateSize(td, false);
\t\tthis.updateInnerHtml(td);
\t\t
\t\tvar w = Math.round(this.bounds.width / this.scale);

\t\tif (this.wrap && w > 0)
\t\t{
\t\t\ttd.style.whiteSpace = 'normal';
\t\t\ttd.style.wordWrap = mxConstants.WORD_WRAP;
\t\t\tow = w;
\t\t\t
\t\t\tif (this.clipped)
\t\t\t{
\t\t\t\tow = Math.min(ow, this.bounds.width);
\t\t\t}

\t\t\ttd.style.width = ow + 'px';
\t\t}
\t\telse
\t\t{
\t\t\ttd.style.whiteSpace = 'nowrap';
\t\t}
\t\t
\t\tsizeDiv = td;
\t\t
\t\tif (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
\t\t{
\t\t\tsizeDiv = sizeDiv.firstChild;
\t\t\t
\t\t\tif (this.wrap && td.style.wordWrap == 'break-word')
\t\t\t{
\t\t\t\tsizeDiv.style.width = '100%';
\t\t\t}
\t\t}

\t\t// Required to update the height of the text box after wrapping width is known 
\t\tif (!this.clipped && this.wrap && w > 0)
\t\t{
\t\t\tow = sizeDiv.offsetWidth + this.textWidthPadding;
\t\t\ttd.style.width = ow + 'px';
\t\t}
\t\t
\t\toh = sizeDiv.offsetHeight + 2;
\t\t
\t\tif (mxClient.IS_QUIRKS && this.border != null && this.border != mxConstants.NONE)
\t\t{
\t\t\toh += 3;
\t\t}
\t}
\telse if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
\t{
\t\tsizeDiv = sizeDiv.firstChild;
\t\toh = sizeDiv.offsetHeight;
\t}

\tow = sizeDiv.offsetWidth + this.textWidthPadding;
\t
\tif (this.clipped)
\t{
\t\toh = Math.min(oh, this.bounds.height);
\t}

\tvar w = this.bounds.width / s;
\tvar h = this.bounds.height / s;

\t// Handles special case for live preview with no wrapper DIV and no textDiv
\tif (this.overflow == 'fill')
\t{
\t\toh = h;
\t\tow = w;
\t}
\telse if (this.overflow == 'width')
\t{
\t\toh = sizeDiv.scrollHeight;
\t\tow = w;
\t}
\t
\t// Stores for later use
\tthis.offsetWidth = ow;
\tthis.offsetHeight = oh;
\t
\t// Simulates max-height CSS in quirks mode
\tif (mxClient.IS_QUIRKS && (this.clipped || (this.overflow == 'width' && h > 0)))
\t{
\t\th = Math.min(h, oh);
\t\tstyle.height = Math.round(h) + 'px';
\t}
\telse
\t{
\t\th = oh;
\t}

\tif (this.overflow != 'fill' && this.overflow != 'width')
\t{
\t\tif (this.clipped)
\t\t{
\t\t\tow = Math.min(w, ow);
\t\t}
\t\t
\t\tw = ow;

\t\t// Simulates max-width CSS in quirks mode
\t\tif ((mxClient.IS_QUIRKS && this.clipped) || this.wrap)
\t\t{
\t\t\tstyle.width = Math.round(w) + 'px';
\t\t}
\t}

\th *= s;
\tw *= s;
\t
\t// Rotation case is handled via VML canvas
\tvar rad = this.getTextRotation() * (Math.PI / 180);
\t
\t// Precalculate cos and sin for the rotation
\tvar real_cos = parseFloat(parseFloat(Math.cos(rad)).toFixed(8));
\tvar real_sin = parseFloat(parseFloat(Math.sin(-rad)).toFixed(8));

\trad %= 2 * Math.PI;
\t
\tif (rad < 0)
\t{
\t\trad += 2 * Math.PI;
\t}
\t
\trad %= Math.PI;
\t
\tif (rad > Math.PI / 2)
\t{
\t\trad = Math.PI - rad;
\t}
\t
\tvar cos = Math.cos(rad);
\tvar sin = Math.sin(-rad);

\tvar tx = w * -(dx + 0.5);
\tvar ty = h * -(dy + 0.5);

\tvar top_fix = (h - h * cos + w * sin) / 2 + real_sin * tx - real_cos * ty;
\tvar left_fix = (w - w * cos + h * sin) / 2 - real_cos * tx - real_sin * ty;
\t
\tif (rad != 0)
\t{
\t\tvar f = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + real_cos + ', M12='+
\t\t\treal_sin + ', M21=' + (-real_sin) + ', M22=' + real_cos + ', sizingMethod=\\'auto expand\\')';
\t\t
\t\tif (style.filter != null && style.filter.length > 0)
\t\t{
\t\t\tstyle.filter += ' ' + f;
\t\t}
\t\telse
\t\t{
\t\t\tstyle.filter = f;
\t\t}
\t}
\t
\t// Workaround for rendering offsets
\tvar dy = 0;
\t
\tif (this.overflow != 'fill' && mxClient.IS_QUIRKS)
\t{
\t\tif (this.valign == mxConstants.ALIGN_TOP)
\t\t{
\t\t\tdy -= 1;
\t\t}
\t\telse if (this.valign == mxConstants.ALIGN_BOTTOM)
\t\t{
\t\t\tdy += 2;
\t\t}
\t\telse
\t\t{
\t\t\tdy += 1;
\t\t}
\t}

\tstyle.zoom = s;
\tstyle.left = Math.round(this.bounds.x + left_fix - w / 2) + 'px';
\tstyle.top = Math.round(this.bounds.y + top_fix - h / 2 + dy) + 'px';
};

/**
 * Function: updateValue
 *
 * Updates the HTML node(s) to reflect the latest bounds and scale.
 */
mxText.prototype.updateValue = function()
{
\tif (mxUtils.isNode(this.value))
\t{
\t\tthis.node.innerHTML = '';
\t\tthis.node.appendChild(this.value);
\t}
\telse
\t{
\t\tvar val = this.value;
\t\t
\t\tif (this.dialect != mxConstants.DIALECT_STRICTHTML)
\t\t{
\t\t\tval = mxUtils.htmlEntities(val, false);
\t\t}
\t\t
\t\t// Handles trailing newlines to make sure they are visible in rendering output
\t\tval = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');
\t\tval = (this.replaceLinefeeds) ? val.replace(/\\n/g, '<br/>') : val;
\t\tvar bg = (this.background != null && this.background != mxConstants.NONE) ? this.background : null;
\t\tvar bd = (this.border != null && this.border != mxConstants.NONE) ? this.border : null;

\t\tif (this.overflow == 'fill' || this.overflow == 'width')
\t\t{
\t\t\tif (bg != null)
\t\t\t{
\t\t\t\tthis.node.style.backgroundColor = bg;
\t\t\t}
\t\t\t
\t\t\tif (bd != null)
\t\t\t{
\t\t\t\tthis.node.style.border = '1px solid ' + bd;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar css = '';
\t\t\t
\t\t\tif (bg != null)
\t\t\t{
\t\t\t\tcss += 'background-color:' + mxUtils.htmlEntities(bg) + ';';
\t\t\t}
\t\t\t
\t\t\tif (bd != null)
\t\t\t{
\t\t\t\tcss += 'border:1px solid ' + mxUtils.htmlEntities(bd) + ';';
\t\t\t}
\t\t\t
\t\t\t// Wrapper DIV for background, zoom needed for inline in quirks
\t\t\t// and to measure wrapped font sizes in all browsers
\t\t\t// FIXME: Background size in quirks mode for wrapped text
\t\t\tvar lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' :
\t\t\t\tmxConstants.LINE_HEIGHT;
\t\t\tval = '<div style=\"zoom:1;' + css + 'display:inline-block;_display:inline;text-decoration:inherit;' +
\t\t\t\t'padding-bottom:1px;padding-right:1px;line-height:' + lh + '\">' + val + '</div>';
\t\t}

\t\tthis.node.innerHTML = val;
\t\t
\t\t// Sets text direction
\t\tvar divs = this.node.getElementsByTagName('div');
\t\t
\t\tif (divs.length > 0)
\t\t{
\t\t\tvar dir = this.textDirection;

\t\t\tif (dir == mxConstants.TEXT_DIRECTION_AUTO && this.dialect != mxConstants.DIALECT_STRICTHTML)
\t\t\t{
\t\t\t\tdir = this.getAutoDirection();
\t\t\t}
\t\t\t
\t\t\tif (dir == mxConstants.TEXT_DIRECTION_LTR || dir == mxConstants.TEXT_DIRECTION_RTL)
\t\t\t{
\t\t\t\tdivs[divs.length - 1].setAttribute('dir', dir);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdivs[divs.length - 1].removeAttribute('dir');
\t\t\t}
\t\t}
\t}
};

/**
 * Function: updateFont
 *
 * Updates the HTML node(s) to reflect the latest bounds and scale.
 */
mxText.prototype.updateFont = function(node)
{
\tvar style = node.style;
\t
\tstyle.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
\tstyle.fontSize = this.size + 'px';
\tstyle.fontFamily = this.family;
\tstyle.verticalAlign = 'top';
\tstyle.color = this.color;
\t
\tif ((this.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
\t{
\t\tstyle.fontWeight = 'bold';
\t}
\telse
\t{
\t\tstyle.fontWeight = '';
\t}

\tif ((this.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
\t{
\t\tstyle.fontStyle = 'italic';
\t}
\telse
\t{
\t\tstyle.fontStyle = '';
\t}
\t
\tvar txtDecor = [];
\t
\tif ((this.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t{
\t\ttxtDecor.push('underline');
\t}
\t
\tif ((this.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t{
\t\ttxtDecor.push('line-through');
\t}
\t
\tstyle.textDecoration = txtDecor.join(' ');
\t
\tif (this.align == mxConstants.ALIGN_CENTER)
\t{
\t\tstyle.textAlign = 'center';
\t}
\telse if (this.align == mxConstants.ALIGN_RIGHT)
\t{
\t\tstyle.textAlign = 'right';
\t}
\telse
\t{
\t\tstyle.textAlign = 'left';
\t}
};

/**
 * Function: updateSize
 *
 * Updates the HTML node(s) to reflect the latest bounds and scale.
 */
mxText.prototype.updateSize = function(node, enableWrap)
{
\tvar w = Math.max(0, Math.round(this.bounds.width / this.scale));
\tvar h = Math.max(0, Math.round(this.bounds.height / this.scale));
\tvar style = node.style;
\t
\t// NOTE: Do not use maxWidth here because wrapping will
\t// go wrong if the cell is outside of the viewable area
\tif (this.clipped)
\t{
\t\tstyle.overflow = 'hidden';
\t\t
\t\tif (!mxClient.IS_QUIRKS)
\t\t{
\t\t\tstyle.maxHeight = h + 'px';
\t\t\tstyle.maxWidth = w + 'px';
\t\t}
\t\telse
\t\t{
\t\t\tstyle.width = w + 'px';
\t\t}
\t}
\telse if (this.overflow == 'fill')
\t{
\t\tstyle.width = (w + 1) + 'px';
\t\tstyle.height = (h + 1) + 'px';
\t\tstyle.overflow = 'hidden';
\t}
\telse if (this.overflow == 'width')
\t{
\t\tstyle.width = (w + 1) + 'px';
\t\tstyle.maxHeight = (h + 1) + 'px';
\t\tstyle.overflow = 'hidden';
\t}
\t
\tif (this.wrap && w > 0)
\t{
\t\tstyle.wordWrap = mxConstants.WORD_WRAP;
\t\tstyle.whiteSpace = 'normal';
\t\tstyle.width = w + 'px';

\t\tif (enableWrap && this.overflow != 'fill' && this.overflow != 'width')
\t\t{
\t\t\tvar sizeDiv = node;
\t\t\t
\t\t\tif (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
\t\t\t{
\t\t\t\tsizeDiv = sizeDiv.firstChild;
\t\t\t\t
\t\t\t\tif (node.style.wordWrap == 'break-word')
\t\t\t\t{
\t\t\t\t\tsizeDiv.style.width = '100%';
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar tmp = sizeDiv.offsetWidth;
\t\t\t
\t\t\t// Workaround for text measuring in hidden containers
\t\t\tif (tmp == 0)
\t\t\t{
\t\t\t\tvar prev = node.parentNode;
\t\t\t\tnode.style.visibility = 'hidden';
\t\t\t\tdocument.body.appendChild(node);
\t\t\t\ttmp = sizeDiv.offsetWidth;
\t\t\t\tnode.style.visibility = '';
\t\t\t\tprev.appendChild(node);
\t\t\t}

\t\t\ttmp += 3;
\t\t\t
\t\t\tif (this.clipped)
\t\t\t{
\t\t\t\ttmp = Math.min(tmp, w);
\t\t\t}
\t\t\t
\t\t\tstyle.width = tmp + 'px';
\t\t}
\t}
\telse
\t{
\t\tstyle.whiteSpace = 'nowrap';
\t}
};

/**
 * Function: getMargin
 *
 * Returns the spacing as an <mxPoint>.
 */
mxText.prototype.updateMargin = function()
{
\tthis.margin = mxUtils.getAlignmentAsPoint(this.align, this.valign);
};

/**
 * Function: getSpacing
 *
 * Returns the spacing as an <mxPoint>.
 */
mxText.prototype.getSpacing = function()
{
\tvar dx = 0;
\tvar dy = 0;

\tif (this.align == mxConstants.ALIGN_CENTER)
\t{
\t\tdx = (this.spacingLeft - this.spacingRight) / 2;
\t}
\telse if (this.align == mxConstants.ALIGN_RIGHT)
\t{
\t\tdx = -this.spacingRight - this.baseSpacingRight;
\t}
\telse
\t{
\t\tdx = this.spacingLeft + this.baseSpacingLeft;
\t}

\tif (this.valign == mxConstants.ALIGN_MIDDLE)
\t{
\t\tdy = (this.spacingTop - this.spacingBottom) / 2;
\t}
\telse if (this.valign == mxConstants.ALIGN_BOTTOM)
\t{
\t\tdy = -this.spacingBottom - this.baseSpacingBottom;;
\t}
\telse
\t{
\t\tdy = this.spacingTop + this.baseSpacingTop;
\t}
\t
\treturn new mxPoint(dx, dy);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxTriangle
 * 
 * Implementation of the triangle shape.
 * 
 * Constructor: mxTriangle
 *
 * Constructs a new triangle shape.
 */
function mxTriangle()
{
\tmxActor.call(this);
};

/**
 * Extends mxActor.
 */
mxUtils.extend(mxTriangle, mxActor);

/**
 * Function: isRoundable
 * 
 * Adds roundable support.
 */
mxTriangle.prototype.isRoundable = function()
{
\treturn true;
};

/**
 * Function: redrawPath
 *
 * Draws the path for this shape.
 */
mxTriangle.prototype.redrawPath = function(c, x, y, w, h)
{
\tvar arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
\tthis.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0.5 * h), new mxPoint(0, h)], this.isRounded, arcSize, true);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxHexagon
 * 
 * Implementation of the hexagon shape.
 * 
 * Constructor: mxHexagon
 *
 * Constructs a new hexagon shape.
 */
function mxHexagon()
{
\tmxActor.call(this);
};

/**
 * Extends mxActor.
 */
mxUtils.extend(mxHexagon, mxActor);

/**
 * Function: redrawPath
 *
 * Draws the path for this shape.
 */
mxHexagon.prototype.redrawPath = function(c, x, y, w, h)
{
\tvar arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
\tthis.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),
\t                   new mxPoint(0.25 * w, h), new mxPoint(0, 0.5 * h)], this.isRounded, arcSize, true);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxLine
 *
 * Extends <mxShape> to implement a horizontal line shape.
 * This shape is registered under <mxConstants.SHAPE_LINE> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxLine
 *
 * Constructs a new line shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * stroke - String that defines the stroke color. Default is 'black'. This is
 * stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxLine(bounds, stroke, strokewidth, vertical)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
\tthis.vertical = (vertical != null) ? vertical : this.vertical;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxLine, mxShape);

/**
 * Function: vertical
 * 
 * Whether to paint a vertical line.
 */
mxLine.prototype.vertical = false;

/**
 * Function: paintVertexShape
 * 
 * Redirects to redrawPath for subclasses to work.
 */
mxLine.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tc.begin();

\tif (this.vertical)
\t{
\t\tvar mid = x + w / 2;
\t\tc.moveTo(mid, y);
\t\tc.lineTo(mid, y + h);
\t}
\telse
\t{
\t\tvar mid = y + h / 2;
\t\tc.moveTo(x, mid);
\t\tc.lineTo(x + w, mid);
\t}

\tc.stroke();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxImageShape
 *
 * Extends <mxShape> to implement an image shape. This shape is registered
 * under <mxConstants.SHAPE_IMAGE> in <mxCellRenderer>.
 * 
 * Constructor: mxImageShape
 * 
 * Constructs a new image shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * image - String that specifies the URL of the image. This is stored in
 * <image>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 0. This is stored in <strokewidth>.
 */
function mxImageShape(bounds, image, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.image = image;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
\tthis.shadow = false;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxImageShape, mxRectangleShape);

/**
 * Variable: preserveImageAspect
 *
 * Switch to preserve image aspect. Default is true.
 */
mxImageShape.prototype.preserveImageAspect = true;

/**
 * Function: getSvgScreenOffset
 * 
 * Disables offset in IE9 for crisper image output.
 */
mxImageShape.prototype.getSvgScreenOffset = function()
{
\treturn 0;
};

/**
 * Function: apply
 * 
 * Overrides <mxShape.apply> to replace the fill and stroke colors with the
 * respective values from <mxConstants.STYLE_IMAGE_BACKGROUND> and
 * <mxConstants.STYLE_IMAGE_BORDER>.
 * 
 * Applies the style of the given <mxCellState> to the shape. This
 * implementation assigns the following styles to local fields:
 * 
 * - <mxConstants.STYLE_IMAGE_BACKGROUND> => fill
 * - <mxConstants.STYLE_IMAGE_BORDER> => stroke
 *
 * Parameters:
 *
 * state - <mxCellState> of the corresponding cell.
 */
mxImageShape.prototype.apply = function(state)
{
\tmxShape.prototype.apply.apply(this, arguments);
\t
\tthis.fill = null;
\tthis.stroke = null;
\tthis.gradient = null;
\t
\tif (this.style != null)
\t{
\t\tthis.preserveImageAspect = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_ASPECT, 1) == 1;
\t\t
\t\t// Legacy support for imageFlipH/V
\t\tthis.flipH = this.flipH || mxUtils.getValue(this.style, 'imageFlipH', 0) == 1;
\t\tthis.flipV = this.flipV || mxUtils.getValue(this.style, 'imageFlipV', 0) == 1;
\t}
};

/**
 * Function: isHtmlAllowed
 * 
 * Returns true if HTML is allowed for this shape. This implementation always
 * returns false.
 */
mxImageShape.prototype.isHtmlAllowed = function()
{
\treturn !this.preserveImageAspect;
};

/**
 * Function: createHtml
 *
 * Creates and returns the HTML DOM node(s) to represent
 * this shape. This implementation falls back to <createVml>
 * so that the HTML creation is optional.
 */
mxImageShape.prototype.createHtml = function()
{
\tvar node = document.createElement('div');
\tnode.style.position = 'absolute';

\treturn node;
};

/**
 * Function: isRoundable
 * 
 * Disables inherited roundable support.
 */
mxImageShape.prototype.isRoundable = function(c, x, y, w, h)
{
\treturn false;
};

/**
 * Function: paintVertexShape
 * 
 * Generic background painting implementation.
 */
mxImageShape.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tif (this.image != null)
\t{
\t\tvar fill = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BACKGROUND, null);
\t\tvar stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, null);
\t\t
\t\tif (fill != null)
\t\t{
\t\t\t// Stroke rendering required for shadow
\t\t\tc.setFillColor(fill);
\t\t\tc.setStrokeColor(stroke);
\t\t\tc.rect(x, y, w, h);
\t\t\tc.fillAndStroke();
\t\t}

\t\t// FlipH/V are implicit via mxShape.updateTransform
\t\tc.image(x, y, w, h, this.image, this.preserveImageAspect, false, false);
\t\t
\t\tvar stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, null);
\t\t
\t\tif (stroke != null)
\t\t{
\t\t\tc.setShadow(false);
\t\t\tc.setStrokeColor(stroke);
\t\t\tc.rect(x, y, w, h);
\t\t\tc.stroke();
\t\t}
\t}
\telse
\t{
\t\tmxRectangleShape.prototype.paintBackground.apply(this, arguments);
\t}
};

/**
 * Function: redraw
 * 
 * Overrides <mxShape.redraw> to preserve the aspect ratio of images.
 */
mxImageShape.prototype.redrawHtmlShape = function()
{
\tthis.node.style.left = Math.round(this.bounds.x) + 'px';
\tthis.node.style.top = Math.round(this.bounds.y) + 'px';
\tthis.node.style.width = Math.max(0, Math.round(this.bounds.width)) + 'px';
\tthis.node.style.height = Math.max(0, Math.round(this.bounds.height)) + 'px';
\tthis.node.innerHTML = '';

\tif (this.image != null)
\t{
\t\tvar fill = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BACKGROUND, '');
\t\tvar stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, '');
\t\tthis.node.style.backgroundColor = fill;
\t\tthis.node.style.borderColor = stroke;
\t\t
\t\t// VML image supports PNG in IE6
\t\tvar useVml = mxClient.IS_IE6 || ((document.documentMode == null || document.documentMode <= 8) && this.rotation != 0);
\t\tvar img = document.createElement((useVml) ? mxClient.VML_PREFIX + ':image' : 'img');
\t\timg.setAttribute('border', '0');
\t\timg.style.position = 'absolute';
\t\timg.src = this.image;

\t\tvar filter = (this.opacity < 100) ? 'alpha(opacity=' + this.opacity + ')' : '';
\t\tthis.node.style.filter = filter;
\t\t
\t\tif (this.flipH && this.flipV)
\t\t{
\t\t\tfilter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)';
\t\t}
\t\telse if (this.flipH)
\t\t{
\t\t\tfilter += 'progid:DXImageTransform.Microsoft.BasicImage(mirror=1)';
\t\t}
\t\telse if (this.flipV)
\t\t{
\t\t\tfilter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)';
\t\t}

\t\tif (img.style.filter != filter)
\t\t{
\t\t\timg.style.filter = filter;
\t\t}

\t\tif (img.nodeName == 'image')
\t\t{
\t\t\timg.style.rotation = this.rotation;
\t\t}
\t\telse if (this.rotation != 0)
\t\t{
\t\t\t// LATER: Add flipV/H support
\t\t\tmxUtils.setPrefixedStyle(img.style, 'transform', 'rotate(' + this.rotation + 'deg)');
\t\t}
\t\telse
\t\t{
\t\t\tmxUtils.setPrefixedStyle(img.style, 'transform', '');
\t\t}

\t\t// Known problem: IE clips top line of image for certain angles
\t\timg.style.width = this.node.style.width;
\t\timg.style.height = this.node.style.height;
\t\t
\t\tthis.node.style.backgroundImage = '';
\t\tthis.node.appendChild(img);
\t}
\telse
\t{
\t\tthis.setTransparentBackgroundImage(this.node);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxLabel
 *
 * Extends <mxShape> to implement an image shape with a label.
 * This shape is registered under <mxConstants.SHAPE_LABEL> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxLabel
 *
 * Constructs a new label shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxLabel(bounds, fill, stroke, strokewidth)
{
\tmxRectangleShape.call(this, bounds, fill, stroke, strokewidth);
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxLabel, mxRectangleShape);

/**
 * Variable: imageSize
 *
 * Default width and height for the image. Default is
 * <mxConstants.DEFAULT_IMAGESIZE>.
 */
mxLabel.prototype.imageSize = mxConstants.DEFAULT_IMAGESIZE;

/**
 * Variable: spacing
 *
 * Default value for image spacing. Default is 2.
 */
mxLabel.prototype.spacing = 2;

/**
 * Variable: indicatorSize
 *
 * Default width and height for the indicicator. Default is 10.
 */
mxLabel.prototype.indicatorSize = 10;

/**
 * Variable: indicatorSpacing
 *
 * Default spacing between image and indicator. Default is 2.
 */
mxLabel.prototype.indicatorSpacing = 2;

/**
 * Function: init
 *
 * Initializes the shape and the <indicator>.
 */
mxLabel.prototype.init = function(container)
{
\tmxShape.prototype.init.apply(this, arguments);

\tif (this.indicatorShape != null)
\t{
\t\tthis.indicator = new this.indicatorShape();
\t\tthis.indicator.dialect = this.dialect;
\t\tthis.indicator.init(this.node);
\t}
};

/**
 * Function: redraw
 *
 * Reconfigures this shape. This will update the colors of the indicator
 * and reconfigure it if required.
 */
mxLabel.prototype.redraw = function()
{
\tif (this.indicator != null)
\t{
\t\tthis.indicator.fill = this.indicatorColor;
\t\tthis.indicator.stroke = this.indicatorStrokeColor;
\t\tthis.indicator.gradient = this.indicatorGradientColor;
\t\tthis.indicator.direction = this.indicatorDirection;
\t\tthis.indicator.redraw();
\t}
\t
\tmxShape.prototype.redraw.apply(this, arguments);
};

/**
 * Function: isHtmlAllowed
 *
 * Returns true for non-rounded, non-rotated shapes with no glass gradient and
 * no indicator shape.
 */
mxLabel.prototype.isHtmlAllowed = function()
{
\treturn mxRectangleShape.prototype.isHtmlAllowed.apply(this, arguments) &&
\t\tthis.indicatorColor == null && this.indicatorShape == null;
};

/**
 * Function: paintForeground
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.paintForeground = function(c, x, y, w, h)
{
\tthis.paintImage(c, x, y, w, h);
\tthis.paintIndicator(c, x, y, w, h);
\t
\tmxRectangleShape.prototype.paintForeground.apply(this, arguments);
};

/**
 * Function: paintImage
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.paintImage = function(c, x, y, w, h)
{
\tif (this.image != null)
\t{
\t\tvar bounds = this.getImageBounds(x, y, w, h);
\t\tc.image(bounds.x, bounds.y, bounds.width, bounds.height, this.image, false, false, false);
\t}
};

/**
 * Function: getImageBounds
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.getImageBounds = function(x, y, w, h)
{
\tvar align = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_LEFT);
\tvar valign = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
\tvar width = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_WIDTH, mxConstants.DEFAULT_IMAGESIZE);
\tvar height = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_HEIGHT, mxConstants.DEFAULT_IMAGESIZE);
\tvar spacing = mxUtils.getNumber(this.style, mxConstants.STYLE_SPACING, this.spacing) + 5;

\tif (align == mxConstants.ALIGN_CENTER)
\t{
\t\tx += (w - width) / 2;
\t}
\telse if (align == mxConstants.ALIGN_RIGHT)
\t{
\t\tx += w - width - spacing;
\t}
\telse // default is left
\t{
\t\tx += spacing;
\t}

\tif (valign == mxConstants.ALIGN_TOP)
\t{
\t\ty += spacing;
\t}
\telse if (valign == mxConstants.ALIGN_BOTTOM)
\t{
\t\ty += h - height - spacing;
\t}
\telse // default is middle
\t{
\t\ty += (h - height) / 2;
\t}
\t
\treturn new mxRectangle(x, y, width, height);
};

/**
 * Function: paintIndicator
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.paintIndicator = function(c, x, y, w, h)
{
\tif (this.indicator != null)
\t{
\t\tthis.indicator.bounds = this.getIndicatorBounds(x, y, w, h);
\t\tthis.indicator.paint(c);
\t}
\telse if (this.indicatorImage != null)
\t{
\t\tvar bounds = this.getIndicatorBounds(x, y, w, h);
\t\tc.image(bounds.x, bounds.y, bounds.width, bounds.height, this.indicatorImage, false, false, false);
\t}
};

/**
 * Function: getIndicatorBounds
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.getIndicatorBounds = function(x, y, w, h)
{
\tvar align = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_LEFT);
\tvar valign = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
\tvar width = mxUtils.getNumber(this.style, mxConstants.STYLE_INDICATOR_WIDTH, this.indicatorSize);
\tvar height = mxUtils.getNumber(this.style, mxConstants.STYLE_INDICATOR_HEIGHT, this.indicatorSize);
\tvar spacing = this.spacing + 5;\t\t
\t
\tif (align == mxConstants.ALIGN_RIGHT)
\t{
\t\tx += w - width - spacing;
\t}
\telse if (align == mxConstants.ALIGN_CENTER)
\t{
\t\tx += (w - width) / 2;
\t}
\telse // default is left
\t{
\t\tx += spacing;
\t}
\t
\tif (valign == mxConstants.ALIGN_BOTTOM)
\t{
\t\ty += h - height - spacing;
\t}
\telse if (valign == mxConstants.ALIGN_TOP)
\t{
\t\ty += spacing;
\t}
\telse // default is middle
\t{
\t\ty += (h - height) / 2;
\t}
\t
\treturn new mxRectangle(x, y, width, height);
};
/**
 * Function: redrawHtmlShape
 * 
 * Generic background painting implementation.
 */
mxLabel.prototype.redrawHtmlShape = function()
{
\tmxRectangleShape.prototype.redrawHtmlShape.apply(this, arguments);
\t
\t// Removes all children
\twhile(this.node.hasChildNodes())
\t{
\t\tthis.node.removeChild(this.node.lastChild);
\t}
\t
\tif (this.image != null)
\t{
\t\tvar node = document.createElement('img');
\t\tnode.style.position = 'relative';
\t\tnode.setAttribute('border', '0');
\t\t
\t\tvar bounds = this.getImageBounds(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
\t\tbounds.x -= this.bounds.x;
\t\tbounds.y -= this.bounds.y;

\t\tnode.style.left = Math.round(bounds.x) + 'px';
\t\tnode.style.top = Math.round(bounds.y) + 'px';
\t\tnode.style.width = Math.round(bounds.width) + 'px';
\t\tnode.style.height = Math.round(bounds.height) + 'px';
\t\t
\t\tnode.src = this.image;
\t\t
\t\tthis.node.appendChild(node);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCylinder
 *
 * Extends <mxShape> to implement an cylinder shape. If a
 * custom shape with one filled area and an overlay path is
 * needed, then this shape's <redrawPath> should be overridden.
 * This shape is registered under <mxConstants.SHAPE_CYLINDER>
 * in <mxCellRenderer>.
 * 
 * Constructor: mxCylinder
 *
 * Constructs a new cylinder shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxCylinder(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxCylinder, mxShape);

/**
 * Variable: maxHeight
 *
 * Defines the maximum height of the top and bottom part
 * of the cylinder shape.
 */
mxCylinder.prototype.maxHeight = 40;

/**
 * Variable: svgStrokeTolerance
 *
 * Sets stroke tolerance to 0 for SVG.
 */
mxCylinder.prototype.svgStrokeTolerance = 0;

/**
 * Function: paintVertexShape
 * 
 * Redirects to redrawPath for subclasses to work.
 */
mxCylinder.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tc.translate(x, y);
\tc.begin();
\tthis.redrawPath(c, x, y, w, h, false);
\tc.fillAndStroke();
\t
\tif (!this.outline || this.style == null || mxUtils.getValue(
\t\tthis.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0)
\t{
\t\tc.setShadow(false);
\t\tc.begin();
\t\tthis.redrawPath(c, x, y, w, h, true);
\t\tc.stroke();
\t}
};

/**
 * Function: getCylinderSize
 *
 * Returns the cylinder size.
 */
mxCylinder.prototype.getCylinderSize = function(x, y, w, h)
{
\treturn Math.min(this.maxHeight, Math.round(h / 5));
};

/**
 * Function: redrawPath
 *
 * Draws the path for this shape.
 */
mxCylinder.prototype.redrawPath = function(c, x, y, w, h, isForeground)
{
\tvar dy = this.getCylinderSize(x, y, w, h);
\t
\tif ((isForeground && this.fill != null) || (!isForeground && this.fill == null))
\t{
\t\tc.moveTo(0, dy);
\t\tc.curveTo(0, 2 * dy, w, 2 * dy, w, dy);
\t\t
\t\t// Needs separate shapes for correct hit-detection
\t\tif (!isForeground)
\t\t{
\t\t\tc.stroke();
\t\t\tc.begin();
\t\t}
\t}
\t
\tif (!isForeground)
\t{
\t\tc.moveTo(0, dy);
\t\tc.curveTo(0, -dy / 3, w, -dy / 3, w, dy);
\t\tc.lineTo(w, h - dy);
\t\tc.curveTo(w, h + dy / 3, 0, h + dy / 3, 0, h - dy);
\t\tc.close();
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxConnector
 * 
 * Extends <mxShape> to implement a connector shape. The connector
 * shape allows for arrow heads on either side.
 * 
 * This shape is registered under <mxConstants.SHAPE_CONNECTOR> in
 * <mxCellRenderer>.
 * 
 * Constructor: mxConnector
 * 
 * Constructs a new connector shape.
 * 
 * Parameters:
 * 
 * points - Array of <mxPoints> that define the points. This is stored in
 * <mxShape.points>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * Default is 'black'.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxConnector(points, stroke, strokewidth)
{
\tmxPolyline.call(this, points, stroke, strokewidth);
};

/**
 * Extends mxPolyline.
 */
mxUtils.extend(mxConnector, mxPolyline);

/**
 * Function: updateBoundingBox
 *
 * Updates the <boundingBox> for this shape using <createBoundingBox> and
 * <augmentBoundingBox> and stores the result in <boundingBox>.
 */
mxConnector.prototype.updateBoundingBox = function()
{
\tthis.useSvgBoundingBox = this.style != null && this.style[mxConstants.STYLE_CURVED] == 1;
\tmxShape.prototype.updateBoundingBox.apply(this, arguments);
};

/**
 * Function: paintEdgeShape
 * 
 * Paints the line shape.
 */
mxConnector.prototype.paintEdgeShape = function(c, pts)
{
\t// The indirection via functions for markers is needed in
\t// order to apply the offsets before painting the line and
\t// paint the markers after painting the line.
\tvar sourceMarker = this.createMarker(c, pts, true);
\tvar targetMarker = this.createMarker(c, pts, false);

\tmxPolyline.prototype.paintEdgeShape.apply(this, arguments);
\t
\t// Disables shadows, dashed styles and fixes fill color for markers
\tc.setFillColor(this.stroke);
\tc.setShadow(false);
\tc.setDashed(false);
\t
\tif (sourceMarker != null)
\t{
\t\tsourceMarker();
\t}
\t
\tif (targetMarker != null)
\t{
\t\ttargetMarker();
\t}
};

/**
 * Function: createMarker
 * 
 * Prepares the marker by adding offsets in pts and returning a function to
 * paint the marker.
 */
mxConnector.prototype.createMarker = function(c, pts, source)
{
\tvar result = null;
\tvar n = pts.length;
\tvar type = mxUtils.getValue(this.style, (source) ? mxConstants.STYLE_STARTARROW : mxConstants.STYLE_ENDARROW);
\tvar p0 = (source) ? pts[1] : pts[n - 2];
\tvar pe = (source) ? pts[0] : pts[n - 1];
\t
\tif (type != null && p0 != null && pe != null)
\t{
\t\tvar count = 1;
\t\t
\t\t// Uses next non-overlapping point
\t\twhile (count < n - 1 && Math.round(p0.x - pe.x) == 0 && Math.round(p0.y - pe.y) == 0)
\t\t{
\t\t\tp0 = (source) ? pts[1 + count] : pts[n - 2 - count];
\t\t\tcount++;
\t\t}
\t
\t\t// Computes the norm and the inverse norm
\t\tvar dx = pe.x - p0.x;
\t\tvar dy = pe.y - p0.y;
\t
\t\tvar dist = Math.max(1, Math.sqrt(dx * dx + dy * dy));
\t\t
\t\tvar unitX = dx / dist;
\t\tvar unitY = dy / dist;
\t
\t\tvar size = mxUtils.getNumber(this.style, (source) ? mxConstants.STYLE_STARTSIZE : mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE);
\t\t
\t\t// Allow for stroke width in the end point used and the 
\t\t// orthogonal vectors describing the direction of the marker
\t\tvar filled = this.style[(source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL] != 0;
\t\t
\t\tresult = mxMarker.createMarker(c, this, type, pe, unitX, unitY, size, source, this.strokewidth, filled);
\t}
\t
\treturn result;
};

/**
 * Function: augmentBoundingBox
 *
 * Augments the bounding box with the strokewidth and shadow offsets.
 */
mxConnector.prototype.augmentBoundingBox = function(bbox)
{
\tmxShape.prototype.augmentBoundingBox.apply(this, arguments);
\t
\t// Adds marker sizes
\tvar size = 0;
\t
\tif (mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, mxConstants.NONE) != mxConstants.NONE)
\t{
\t\tsize = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE) + 1;
\t}
\t
\tif (mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, mxConstants.NONE) != mxConstants.NONE)
\t{
\t\tsize = Math.max(size, mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE)) + 1;
\t}
\t
\tbbox.grow(size * this.scale);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSwimlane
 *
 * Extends <mxShape> to implement a swimlane shape. This shape is registered
 * under <mxConstants.SHAPE_SWIMLANE> in <mxCellRenderer>. Use the
 * <mxConstants.STYLE_STYLE_STARTSIZE> to define the size of the title
 * region, <mxConstants.STYLE_SWIMLANE_FILLCOLOR> for the content area fill,
 * <mxConstants.STYLE_SEPARATORCOLOR> to draw an additional vertical separator
 * and <mxConstants.STYLE_SWIMLANE_LINE> to hide the line between the title
 * region and the content area. The <mxConstants.STYLE_HORIZONTAL> affects
 * the orientation of this shape, not only its label.
 * 
 * Constructor: mxSwimlane
 *
 * Constructs a new swimlane shape.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that defines the bounds. This is stored in
 * <mxShape.bounds>.
 * fill - String that defines the fill color. This is stored in <fill>.
 * stroke - String that defines the stroke color. This is stored in <stroke>.
 * strokewidth - Optional integer that defines the stroke width. Default is
 * 1. This is stored in <strokewidth>.
 */
function mxSwimlane(bounds, fill, stroke, strokewidth)
{
\tmxShape.call(this);
\tthis.bounds = bounds;
\tthis.fill = fill;
\tthis.stroke = stroke;
\tthis.strokewidth = (strokewidth != null) ? strokewidth : 1;
};

/**
 * Extends mxShape.
 */
mxUtils.extend(mxSwimlane, mxShape);

/**
 * Variable: imageSize
 *
 * Default imagewidth and imageheight if an image but no imagewidth
 * and imageheight are defined in the style. Value is 16.
 */
mxSwimlane.prototype.imageSize = 16;

/**
 * Function: isRoundable
 * 
 * Adds roundable support.
 */
mxSwimlane.prototype.isRoundable = function(c, x, y, w, h)
{
\treturn true;
};

/**
 * Function: getTitleSize
 * 
 * Returns the title size.
 */
mxSwimlane.prototype.getTitleSize = function()
{
\treturn Math.max(0, mxUtils.getValue(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
};

/**
 * Function: getLabelBounds
 * 
 * Returns the bounding box for the label.
 */
mxSwimlane.prototype.getLabelBounds = function(rect)
{
\tvar start = this.getTitleSize();
\tvar bounds = new mxRectangle(rect.x, rect.y, rect.width, rect.height);
\tvar horizontal = this.isHorizontal();
\t
\tvar flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, 0) == 1;
\tvar flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, 0) == 1;\t
\t
\t// East is default
\tvar shapeVertical = (this.direction == mxConstants.DIRECTION_NORTH ||
\t\t\tthis.direction == mxConstants.DIRECTION_SOUTH);
\tvar realHorizontal = horizontal == !shapeVertical;
\t
\tvar realFlipH = !realHorizontal && flipH != (this.direction == mxConstants.DIRECTION_SOUTH ||
\t\t\tthis.direction == mxConstants.DIRECTION_WEST);
\tvar realFlipV = realHorizontal && flipV != (this.direction == mxConstants.DIRECTION_SOUTH ||
\t\t\tthis.direction == mxConstants.DIRECTION_WEST);

\t// Shape is horizontal
\tif (!shapeVertical)
\t{
\t\tvar tmp = Math.min(bounds.height, start * this.scale);

\t\tif (realFlipH || realFlipV)
\t\t{
\t\t\tbounds.y += bounds.height - tmp;
\t\t}

\t\tbounds.height = tmp;
\t}
\telse
\t{
\t\tvar tmp = Math.min(bounds.width, start * this.scale);
\t\t
\t\tif (realFlipH || realFlipV)
\t\t{
\t\t\tbounds.x += bounds.width - tmp;\t
\t\t}

\t\tbounds.width = tmp;
\t}
\t
\treturn bounds;
};

/**
 * Function: getGradientBounds
 * 
 * Returns the bounding box for the gradient box for this shape.
 */
mxSwimlane.prototype.getGradientBounds = function(c, x, y, w, h)
{
\tvar start = this.getTitleSize();
\t
\tif (this.isHorizontal())
\t{
\t\tstart = Math.min(start, h);
\t\treturn new mxRectangle(x, y, w, start);
\t}
\telse
\t{
\t\tstart = Math.min(start, w);
\t\treturn new mxRectangle(x, y, start, h);
\t}
};

/**
 * Function: getSwimlaneArcSize
 * 
 * Returns the arcsize for the swimlane.
 */
mxSwimlane.prototype.getSwimlaneArcSize = function(w, h, start)
{
\tif (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
\t{
\t\treturn Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
\t\t\tmxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
\t}
\telse
\t{
\t\tvar f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;

\t\treturn start * f * 3; 
\t}
};

/**
 * Function: isHorizontal
 *
 * Paints the swimlane vertex shape.
 */
mxSwimlane.prototype.isHorizontal = function()
{
\treturn mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, 1) == 1;
};

/**
 * Function: paintVertexShape
 *
 * Paints the swimlane vertex shape.
 */
mxSwimlane.prototype.paintVertexShape = function(c, x, y, w, h)
{
\tvar start = this.getTitleSize();
\tvar fill = mxUtils.getValue(this.style, mxConstants.STYLE_SWIMLANE_FILLCOLOR, mxConstants.NONE);
\tvar swimlaneLine = mxUtils.getValue(this.style, mxConstants.STYLE_SWIMLANE_LINE, 1) == 1;
\tvar r = 0;
\t
\tif (this.isHorizontal())
\t{
\t\tstart = Math.min(start, h);
\t}
\telse
\t{
\t\tstart = Math.min(start, w);
\t}
\t
\tc.translate(x, y);
\t
\tif (!this.isRounded)
\t{
\t\tthis.paintSwimlane(c, x, y, w, h, start, fill, swimlaneLine);
\t}
\telse
\t{
\t\tr = this.getSwimlaneArcSize(w, h, start);
\t\tr = Math.min(((this.isHorizontal()) ? h : w) - start, Math.min(start, r));
\t\tthis.paintRoundedSwimlane(c, x, y, w, h, start, r, fill, swimlaneLine);
\t}
\t
\tvar sep = mxUtils.getValue(this.style, mxConstants.STYLE_SEPARATORCOLOR, mxConstants.NONE);
\tthis.paintSeparator(c, x, y, w, h, start, sep);

\tif (this.image != null)
\t{
\t\tvar bounds = this.getImageBounds(x, y, w, h);
\t\tc.image(bounds.x - x, bounds.y - y, bounds.width, bounds.height,
\t\t\t\tthis.image, false, false, false);
\t}
\t
\tif (this.glass)
\t{
\t\tc.setShadow(false);
\t\tthis.paintGlassEffect(c, 0, 0, w, start, r);
\t}
};

/**
 * Function: paintSwimlane
 *
 * Paints the swimlane vertex shape.
 */
mxSwimlane.prototype.paintSwimlane = function(c, x, y, w, h, start, fill, swimlaneLine)
{
\tc.begin();
\t
\tvar events = true;
\t
\tif (this.style != null)
\t{
\t\tevents = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
\t}
\t
\tif (!events && (this.fill == null || this.fill == mxConstants.NONE))
\t{
\t\tc.pointerEvents = false;
\t}
\t
\tif (this.isHorizontal())
\t{
\t\tc.moveTo(0, start);
\t\tc.lineTo(0, 0);
\t\tc.lineTo(w, 0);
\t\tc.lineTo(w, start);
\t\tc.fillAndStroke();

\t\tif (start < h)
\t\t{
\t\t\tif (fill == mxConstants.NONE || !events)
\t\t\t{
\t\t\t\tc.pointerEvents = false;
\t\t\t}
\t\t\t
\t\t\tif (fill != mxConstants.NONE)
\t\t\t{
\t\t\t\tc.setFillColor(fill);
\t\t\t}
\t\t\t
\t\t\tc.begin();
\t\t\tc.moveTo(0, start);
\t\t\tc.lineTo(0, h);
\t\t\tc.lineTo(w, h);
\t\t\tc.lineTo(w, start);
\t\t\t
\t\t\tif (fill == mxConstants.NONE)
\t\t\t{
\t\t\t\tc.stroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tc.fillAndStroke();
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tc.moveTo(start, 0);
\t\tc.lineTo(0, 0);
\t\tc.lineTo(0, h);
\t\tc.lineTo(start, h);
\t\tc.fillAndStroke();
\t\t
\t\tif (start < w)
\t\t{
\t\t\tif (fill == mxConstants.NONE || !events)
\t\t\t{
\t\t\t\tc.pointerEvents = false;
\t\t\t}
\t\t\t
\t\t\tif (fill != mxConstants.NONE)
\t\t\t{
\t\t\t\tc.setFillColor(fill);
\t\t\t}
\t\t\t
\t\t\tc.begin();
\t\t\tc.moveTo(start, 0);
\t\t\tc.lineTo(w, 0);
\t\t\tc.lineTo(w, h);
\t\t\tc.lineTo(start, h);
\t\t\t
\t\t\tif (fill == mxConstants.NONE)
\t\t\t{
\t\t\t\tc.stroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tc.fillAndStroke();
\t\t\t}
\t\t}
\t}
\t
\tif (swimlaneLine)
\t{
\t\tthis.paintDivider(c, x, y, w, h, start, fill == mxConstants.NONE);
\t}
};

/**
 * Function: paintRoundedSwimlane
 *
 * Paints the swimlane vertex shape.
 */
mxSwimlane.prototype.paintRoundedSwimlane = function(c, x, y, w, h, start, r, fill, swimlaneLine)
{
\tc.begin();
\t
\tvar events = true;
\t
\tif (this.style != null)
\t{
\t\tevents = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
\t}
\t
\tif (!events && (this.fill == null || this.fill == mxConstants.NONE))
\t{
\t\tc.pointerEvents = false;
\t}
\t
\tif (this.isHorizontal())
\t{
\t\tc.moveTo(w, start);
\t\tc.lineTo(w, r);
\t\tc.quadTo(w, 0, w - Math.min(w / 2, r), 0);
\t\tc.lineTo(Math.min(w / 2, r), 0);
\t\tc.quadTo(0, 0, 0, r);
\t\tc.lineTo(0, start);
\t\tc.fillAndStroke();
\t\t
\t\tif (start < h)
\t\t{
\t\t\tif (fill == mxConstants.NONE || !events)
\t\t\t{
\t\t\t\tc.pointerEvents = false;
\t\t\t}
\t\t\t
\t\t\tif (fill != mxConstants.NONE)
\t\t\t{
\t\t\t\tc.setFillColor(fill);
\t\t\t}
\t\t\t
\t\t\tc.begin();
\t\t\tc.moveTo(0, start);
\t\t\tc.lineTo(0, h - r);
\t\t\tc.quadTo(0, h, Math.min(w / 2, r), h);
\t\t\tc.lineTo(w - Math.min(w / 2, r), h);
\t\t\tc.quadTo(w, h, w, h - r);
\t\t\tc.lineTo(w, start);
\t\t\t
\t\t\tif (fill == mxConstants.NONE)
\t\t\t{
\t\t\t\tc.stroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tc.fillAndStroke();
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tc.moveTo(start, 0);
\t\tc.lineTo(r, 0);
\t\tc.quadTo(0, 0, 0, Math.min(h / 2, r));
\t\tc.lineTo(0, h - Math.min(h / 2, r));
\t\tc.quadTo(0, h, r, h);
\t\tc.lineTo(start, h);
\t\tc.fillAndStroke();

\t\tif (start < w)
\t\t{
\t\t\tif (fill == mxConstants.NONE || !events)
\t\t\t{
\t\t\t\tc.pointerEvents = false;
\t\t\t}
\t\t\t
\t\t\tif (fill != mxConstants.NONE)
\t\t\t{
\t\t\t\tc.setFillColor(fill);
\t\t\t}
\t\t\t
\t\t\tc.begin();
\t\t\tc.moveTo(start, h);
\t\t\tc.lineTo(w - r, h);
\t\t\tc.quadTo(w, h, w, h - Math.min(h / 2, r));
\t\t\tc.lineTo(w, Math.min(h / 2, r));
\t\t\tc.quadTo(w, 0, w - r, 0);
\t\t\tc.lineTo(start, 0);
\t\t\t
\t\t\tif (fill == mxConstants.NONE)
\t\t\t{
\t\t\t\tc.stroke();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tc.fillAndStroke();
\t\t\t}
\t\t}
\t}

\tif (swimlaneLine)
\t{
\t\tthis.paintDivider(c, x, y, w, h, start, fill == mxConstants.NONE);
\t}
};

/**
 * Function: paintDivider
 *
 * Paints the divider between swimlane title and content area.
 */
mxSwimlane.prototype.paintDivider = function(c, x, y, w, h, start, shadow)
{
\tif (!shadow)
\t{
\t\tc.setShadow(false);
\t}

\tc.begin();
\t
\tif (this.isHorizontal())
\t{
\t\tc.moveTo(0, start);
\t\tc.lineTo(w, start);
\t}
\telse
\t{
\t\tc.moveTo(start, 0);
\t\tc.lineTo(start, h);
\t}

\tc.stroke();
};

/**
 * Function: paintSeparator
 *
 * Paints the vertical or horizontal separator line between swimlanes.
 */
mxSwimlane.prototype.paintSeparator = function(c, x, y, w, h, start, color)
{
\tif (color != mxConstants.NONE)
\t{
\t\tc.setStrokeColor(color);
\t\tc.setDashed(true);
\t\tc.begin();
\t\t
\t\tif (this.isHorizontal())
\t\t{
\t\t\tc.moveTo(w, start);
\t\t\tc.lineTo(w, h);
\t\t}
\t\telse
\t\t{
\t\t\tc.moveTo(start, 0);
\t\t\tc.lineTo(w, 0);
\t\t}
\t\t
\t\tc.stroke();
\t\tc.setDashed(false);
\t}
};

/**
 * Function: getImageBounds
 *
 * Paints the swimlane vertex shape.
 */
mxSwimlane.prototype.getImageBounds = function(x, y, w, h)
{
\tif (this.isHorizontal())
\t{
\t\treturn new mxRectangle(x + w - this.imageSize, y, this.imageSize, this.imageSize);
\t}
\telse
\t{
\t\treturn new mxRectangle(x, y, this.imageSize, this.imageSize);
\t}
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxGraphLayout
 * 
 * Base class for all layout algorithms in mxGraph. Main public functions are
 * <moveCell> for handling a moved cell within a layouted parent, and <execute> for
 * running the layout on a given parent cell.
 *
 * Known Subclasses:
 *
 * <mxCircleLayout>, <mxCompactTreeLayout>, <mxCompositeLayout>,
 * <mxFastOrganicLayout>, <mxParallelEdgeLayout>, <mxPartitionLayout>,
 * <mxStackLayout>
 * 
 * Constructor: mxGraphLayout
 *
 * Constructs a new layout using the given layouts.
 *
 * Arguments:
 * 
 * graph - Enclosing 
 */
function mxGraphLayout(graph)
{
\tthis.graph = graph;
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxGraphLayout.prototype.graph = null;

/**
 * Variable: useBoundingBox
 *
 * Boolean indicating if the bounding box of the label should be used if
 * its available. Default is true.
 */
mxGraphLayout.prototype.useBoundingBox = true;

/**
 * Variable: parent
 *
 * The parent cell of the layout, if any
 */
mxGraphLayout.prototype.parent = null;

/**
 * Function: moveCell
 * 
 * Notified when a cell is being moved in a parent that has automatic
 * layout to update the cell state (eg. index) so that the outcome of the
 * layout will position the vertex as close to the point (x, y) as
 * possible.
 * 
 * Empty implementation.
 * 
 * Parameters:
 * 
 * cell - <mxCell> which has been moved.
 * x - X-coordinate of the new cell location.
 * y - Y-coordinate of the new cell location.
 */
mxGraphLayout.prototype.moveCell = function(cell, x, y) { };

/**
 * Function: resizeCell
 * 
 * Notified when a cell is being resized in a parent that has automatic
 * layout to update the other cells in the layout.
 * 
 * Empty implementation.
 * 
 * Parameters:
 * 
 * cell - <mxCell> which has been moved.
 * bounds - <mxRectangle> that represents the new cell bounds.
 */
mxGraphLayout.prototype.resizeCell = function(cell, bounds) { };

/**
 * Function: execute
 * 
 * Executes the layout algorithm for the children of the given parent.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be layed out.
 */
mxGraphLayout.prototype.execute = function(parent) { };

/**
 * Function: getGraph
 * 
 * Returns the graph that this layout operates on.
 */
mxGraphLayout.prototype.getGraph = function()
{
\treturn this.graph;
};

/**
 * Function: getConstraint
 * 
 * Returns the constraint for the given key and cell. The optional edge and
 * source arguments are used to return inbound and outgoing routing-
 * constraints for the given edge and vertex. This implementation always
 * returns the value for the given key in the style of the given cell.
 * 
 * Parameters:
 * 
 * key - Key of the constraint to be returned.
 * cell - <mxCell> whose constraint should be returned.
 * edge - Optional <mxCell> that represents the connection whose constraint
 * should be returned. Default is null.
 * source - Optional boolean that specifies if the connection is incoming
 * or outgoing. Default is null.
 */
mxGraphLayout.prototype.getConstraint = function(key, cell, edge, source)
{
\treturn this.graph.getCurrentCellStyle(cell)[key]
};

/**
 * Function: traverse
 * 
 * Traverses the (directed) graph invoking the given function for each
 * visited vertex and edge. The function is invoked with the current vertex
 * and the incoming edge as a parameter. This implementation makes sure
 * each vertex is only visited once. The function may return false if the
 * traversal should stop at the given vertex.
 * 
 * Example:
 * 
 * (code)
 * mxLog.show();
 * var cell = graph.getSelectionCell();
 * graph.traverse(cell, false, function(vertex, edge)
 * {
 *   mxLog.debug(graph.getLabel(vertex));
 * });
 * (end)
 * 
 * Parameters:
 * 
 * vertex - <mxCell> that represents the vertex where the traversal starts.
 * directed - Optional boolean indicating if edges should only be traversed
 * from source to target. Default is true.
 * func - Visitor function that takes the current vertex and the incoming
 * edge as arguments. The traversal stops if the function returns false.
 * edge - Optional <mxCell> that represents the incoming edge. This is
 * null for the first step of the traversal.
 * visited - Optional <mxDictionary> of cell paths for the visited cells.
 */
mxGraphLayout.traverse = function(vertex, directed, func, edge, visited)
{
\tif (func != null && vertex != null)
\t{
\t\tdirected = (directed != null) ? directed : true;
\t\tvisited = visited || new mxDictionary();
\t\t
\t\tif (!visited.get(vertex))
\t\t{
\t\t\tvisited.put(vertex, true);
\t\t\tvar result = func(vertex, edge);
\t\t\t
\t\t\tif (result == null || result)
\t\t\t{
\t\t\t\tvar edgeCount = this.graph.model.getEdgeCount(vertex);
\t\t\t\t
\t\t\t\tif (edgeCount > 0)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < edgeCount; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar e = this.graph.model.getEdgeAt(vertex, i);
\t\t\t\t\t\tvar isSource = this.graph.model.getTerminal(e, true) == vertex;
\t\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\tif (!directed || isSource)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar next = this.graph.view.getVisibleTerminal(e, !isSource);
\t\t\t\t\t\t\tthis.traverse(next, directed, func, e, visited);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isAncestor
 * 
 * Returns true if the given parent is an ancestor of the given child.
 *
 * Parameters:
 * 
 * parent - <mxCell> that specifies the parent.
 * child - <mxCell> that specifies the child.
 * traverseAncestors - boolean whether to 
 */
mxGraphLayout.prototype.isAncestor = function(parent, child, traverseAncestors)
{
\tif (!traverseAncestors)
\t{
\t\treturn (this.graph.model.getParent(child) == parent);
\t}\t
\t
\tif (child == parent)
\t{
\t\treturn false;
\t}

\twhile (child != null && child != parent)
\t{
\t\tchild = this.graph.model.getParent(child);
\t}
\t
\treturn child == parent;
};

/**
 * Function: isVertexMovable
 * 
 * Returns a boolean indicating if the given <mxCell> is movable or
 * bendable by the algorithm. This implementation returns true if the given
 * cell is movable in the graph.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose movable state should be returned.
 */
mxGraphLayout.prototype.isVertexMovable = function(cell)
{
\treturn this.graph.isCellMovable(cell);
};

/**
 * Function: isVertexIgnored
 * 
 * Returns a boolean indicating if the given <mxCell> should be ignored by
 * the algorithm. This implementation returns false for all vertices.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> whose ignored state should be returned.
 */
mxGraphLayout.prototype.isVertexIgnored = function(vertex)
{
\treturn !this.graph.getModel().isVertex(vertex) ||
\t\t!this.graph.isCellVisible(vertex);
};

/**
 * Function: isEdgeIgnored
 * 
 * Returns a boolean indicating if the given <mxCell> should be ignored by
 * the algorithm. This implementation returns false for all vertices.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose ignored state should be returned.
 */
mxGraphLayout.prototype.isEdgeIgnored = function(edge)
{
\tvar model = this.graph.getModel();
\t
\treturn !model.isEdge(edge) ||
\t\t!this.graph.isCellVisible(edge) ||
\t\tmodel.getTerminal(edge, true) == null ||
\t\tmodel.getTerminal(edge, false) == null;
};

/**
 * Function: setEdgeStyleEnabled
 * 
 * Disables or enables the edge style of the given edge.
 */
mxGraphLayout.prototype.setEdgeStyleEnabled = function(edge, value)
{
\tthis.graph.setCellStyles(mxConstants.STYLE_NOEDGESTYLE,
\t\t\t(value) ? '0' : '1', [edge]);
};

/**
 * Function: setOrthogonalEdge
 * 
 * Disables or enables orthogonal end segments of the given edge.
 */
mxGraphLayout.prototype.setOrthogonalEdge = function(edge, value)
{
\tthis.graph.setCellStyles(mxConstants.STYLE_ORTHOGONAL,
\t\t\t(value) ? '1' : '0', [edge]);
};

/**
 * Function: getParentOffset
 * 
 * Determines the offset of the given parent to the parent
 * of the layout
 */
mxGraphLayout.prototype.getParentOffset = function(parent)
{
\tvar result = new mxPoint();

\tif (parent != null && parent != this.parent)
\t{
\t\tvar model = this.graph.getModel();

\t\tif (model.isAncestor(this.parent, parent))
\t\t{
\t\t\tvar parentGeo = model.getGeometry(parent);

\t\t\twhile (parent != this.parent)
\t\t\t{
\t\t\t\tresult.x = result.x + parentGeo.x;
\t\t\t\tresult.y = result.y + parentGeo.y;

\t\t\t\tparent = model.getParent(parent);;
\t\t\t\tparentGeo = model.getGeometry(parent);
\t\t\t}
\t\t}
\t}

\treturn result;
};

/**
 * Function: setEdgePoints
 * 
 * Replaces the array of mxPoints in the geometry of the given edge
 * with the given array of mxPoints.
 */
mxGraphLayout.prototype.setEdgePoints = function(edge, points)
{
\tif (edge != null)
\t{
\t\tvar model = this.graph.model;
\t\tvar geometry = model.getGeometry(edge);

\t\tif (geometry == null)
\t\t{
\t\t\tgeometry = new mxGeometry();
\t\t\tgeometry.setRelative(true);
\t\t}
\t\telse
\t\t{
\t\t\tgeometry = geometry.clone();
\t\t}

\t\tif (this.parent != null && points != null)
\t\t{
\t\t\tvar parent = model.getParent(edge);

\t\t\tvar parentOffset = this.getParentOffset(parent);

\t\t\tfor (var i = 0; i < points.length; i++)
\t\t\t{
\t\t\t\tpoints[i].x = points[i].x - parentOffset.x;
\t\t\t\tpoints[i].y = points[i].y - parentOffset.y;
\t\t\t}
\t\t}

\t\tgeometry.points = points;
\t\tmodel.setGeometry(edge, geometry);
\t}
};

/**
 * Function: setVertexLocation
 * 
 * Sets the new position of the given cell taking into account the size of
 * the bounding box if <useBoundingBox> is true. The change is only carried
 * out if the new location is not equal to the existing location, otherwise
 * the geometry is not replaced with an updated instance. The new or old
 * bounds are returned (including overlapping labels).
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose geometry is to be set.
 * x - Integer that defines the x-coordinate of the new location.
 * y - Integer that defines the y-coordinate of the new location.
 */
mxGraphLayout.prototype.setVertexLocation = function(cell, x, y)
{
\tvar model = this.graph.getModel();
\tvar geometry = model.getGeometry(cell);
\tvar result = null;
\t
\tif (geometry != null)
\t{
\t\tresult = new mxRectangle(x, y, geometry.width, geometry.height);
\t\t
\t\t// Checks for oversize labels and shifts the result
\t\t// TODO: Use mxUtils.getStringSize for label bounds
\t\tif (this.useBoundingBox)
\t\t{
\t\t\tvar state = this.graph.getView().getState(cell);
\t\t\t
\t\t\tif (state != null && state.text != null && state.text.boundingBox != null)
\t\t\t{
\t\t\t\tvar scale = this.graph.getView().scale;
\t\t\t\tvar box = state.text.boundingBox;
\t\t\t\t
\t\t\t\tif (state.text.boundingBox.x < state.x)
\t\t\t\t{
\t\t\t\t\tx += (state.x - box.x) / scale;
\t\t\t\t\tresult.width = box.width;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (state.text.boundingBox.y < state.y)
\t\t\t\t{
\t\t\t\t\ty += (state.y - box.y) / scale;
\t\t\t\t\tresult.height = box.height;
\t\t\t\t}
\t\t\t}
\t\t}

\t\tif (this.parent != null)
\t\t{
\t\t\tvar parent = model.getParent(cell);

\t\t\tif (parent != null && parent != this.parent)
\t\t\t{
\t\t\t\tvar parentOffset = this.getParentOffset(parent);

\t\t\t\tx = x - parentOffset.x;
\t\t\t\ty = y - parentOffset.y;
\t\t\t}
\t\t}

\t\tif (geometry.x != x || geometry.y != y)
\t\t{
\t\t\tgeometry = geometry.clone();
\t\t\tgeometry.x = x;
\t\t\tgeometry.y = y;
\t\t\t
\t\t\tmodel.setGeometry(cell, geometry);
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getVertexBounds
 * 
 * Returns an <mxRectangle> that defines the bounds of the given cell or
 * the bounding box if <useBoundingBox> is true.
 */
mxGraphLayout.prototype.getVertexBounds = function(cell)
{
\tvar geo = this.graph.getModel().getGeometry(cell);

\t// Checks for oversize label bounding box and corrects
\t// the return value accordingly
\t// TODO: Use mxUtils.getStringSize for label bounds
\tif (this.useBoundingBox)
\t{
\t\tvar state = this.graph.getView().getState(cell);

\t\tif (state != null && state.text != null && state.text.boundingBox != null)
\t\t{
\t\t\tvar scale = this.graph.getView().scale;
\t\t\tvar tmp = state.text.boundingBox;

\t\t\tvar dx0 = Math.max(state.x - tmp.x, 0) / scale;
\t\t\tvar dy0 = Math.max(state.y - tmp.y, 0) / scale;
\t\t\tvar dx1 = Math.max((tmp.x + tmp.width) - (state.x + state.width), 0) / scale;
  \t\t\tvar dy1 = Math.max((tmp.y + tmp.height) - (state.y + state.height), 0) / scale;

\t\t\tgeo = new mxRectangle(geo.x - dx0, geo.y - dy0, geo.width + dx0 + dx1, geo.height + dy0 + dy1);
\t\t}
\t}

\tif (this.parent != null)
\t{
\t\tvar parent = this.graph.getModel().getParent(cell);
\t\tgeo = geo.clone();

\t\tif (parent != null && parent != this.parent)
\t\t{
\t\t\tvar parentOffset = this.getParentOffset(parent);
\t\t\tgeo.x = geo.x + parentOffset.x;
\t\t\tgeo.y = geo.y + parentOffset.y;
\t\t}
\t}

\treturn new mxRectangle(geo.x, geo.y, geo.width, geo.height);
};

/**
 * Function: arrangeGroups
 * 
 * Shortcut to <mxGraph.updateGroupBounds> with moveGroup set to true.
 */
mxGraphLayout.prototype.arrangeGroups = function(cells, border, topBorder, rightBorder, bottomBorder, leftBorder)
{
\treturn this.graph.updateGroupBounds(cells, border, true, topBorder, rightBorder, bottomBorder, leftBorder);
};

/**
 * Class: WeightedCellSorter
 * 
 * A utility class used to track cells whilst sorting occurs on the weighted
 * sum of their connected edges. Does not violate (x.compareTo(y)==0) ==
 * (x.equals(y))
 *
 * Constructor: WeightedCellSorter
 * 
 * Constructs a new weighted cell sorted for the given cell and weight.
 */
function WeightedCellSorter(cell, weightedValue)
{
\tthis.cell = cell;
\tthis.weightedValue = weightedValue;
};

/**
 * Variable: weightedValue
 * 
 * The weighted value of the cell stored.
 */
WeightedCellSorter.prototype.weightedValue = 0;

/**
 * Variable: nudge
 * 
 * Whether or not to flip equal weight values.
 */
WeightedCellSorter.prototype.nudge = false;

/**
 * Variable: visited
 * 
 * Whether or not this cell has been visited in the current assignment.
 */
WeightedCellSorter.prototype.visited = false;

/**
 * Variable: rankIndex
 * 
 * The index this cell is in the model rank.
 */
WeightedCellSorter.prototype.rankIndex = null;

/**
 * Variable: cell
 * 
 * The cell whose median value is being calculated.
 */
WeightedCellSorter.prototype.cell = null;

/**
 * Function: compare
 * 
 * Compares two WeightedCellSorters.
 */
WeightedCellSorter.prototype.compare = function(a, b)
{
\tif (a != null && b != null)
\t{
\t\tif (b.weightedValue > a.weightedValue)
\t\t{
\t\t\treturn -1;
\t\t}
\t\telse if (b.weightedValue < a.weightedValue)
\t\t{
\t\t\treturn 1;
\t\t}
\t\telse
\t\t{
\t\t\tif (b.nudge)
\t\t\t{
\t\t\t\treturn -1;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn 1;
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\treturn 0;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStackLayout
 * 
 * Extends <mxGraphLayout> to create a horizontal or vertical stack of the
 * child vertices. The children do not need to be connected for this layout
 * to work.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxStackLayout(graph, true);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxStackLayout
 * 
 * Constructs a new stack layout layout for the specified graph,
 * spacing, orientation and offset.
 */
function mxStackLayout(graph, horizontal, spacing, x0, y0, border)
{
\tmxGraphLayout.call(this, graph);
\tthis.horizontal = (horizontal != null) ? horizontal : true;
\tthis.spacing = (spacing != null) ? spacing : 0;
\tthis.x0 = (x0 != null) ? x0 : 0;
\tthis.y0 = (y0 != null) ? y0 : 0;
\tthis.border = (border != null) ? border : 0;
};

/**
 * Extends mxGraphLayout.
 */
mxStackLayout.prototype = new mxGraphLayout();
mxStackLayout.prototype.constructor = mxStackLayout;

/**
 * Variable: horizontal
 *
 * Specifies the orientation of the layout. Default is true.
 */
mxStackLayout.prototype.horizontal = null;

/**
 * Variable: spacing
 *
 * Specifies the spacing between the cells. Default is 0.
 */
mxStackLayout.prototype.spacing = null;

/**
 * Variable: x0
 *
 * Specifies the horizontal origin of the layout. Default is 0.
 */
mxStackLayout.prototype.x0 = null;

/**
 * Variable: y0
 *
 * Specifies the vertical origin of the layout. Default is 0.
 */
mxStackLayout.prototype.y0 = null;

/**
 * Variable: border
 *
 * Border to be added if fill is true. Default is 0.
 */
mxStackLayout.prototype.border = 0;

/**
 * Variable: marginTop
 * 
 * Top margin for the child area. Default is 0.
 */
mxStackLayout.prototype.marginTop = 0;

/**
 * Variable: marginLeft
 * 
 * Top margin for the child area. Default is 0.
 */
mxStackLayout.prototype.marginLeft = 0;

/**
 * Variable: marginRight
 * 
 * Top margin for the child area. Default is 0.
 */
mxStackLayout.prototype.marginRight = 0;

/**
 * Variable: marginBottom
 * 
 * Top margin for the child area. Default is 0.
 */
mxStackLayout.prototype.marginBottom = 0;

/**
 * Variable: keepFirstLocation
 * 
 * Boolean indicating if the location of the first cell should be
 * kept, that is, it will not be moved to x0 or y0. Default is false.
 */
mxStackLayout.prototype.keepFirstLocation = false;

/**
 * Variable: fill
 * 
 * Boolean indicating if dimension should be changed to fill out the parent
 * cell. Default is false.
 */
mxStackLayout.prototype.fill = false;
\t
/**
 * Variable: resizeParent
 * 
 * If the parent should be resized to match the width/height of the
 * stack. Default is false.
 */
mxStackLayout.prototype.resizeParent = false;

/**
 * Variable: resizeParentMax
 * 
 * Use maximum of existing value and new value for resize of parent.
 * Default is false.
 */
mxStackLayout.prototype.resizeParentMax = false;

/**
 * Variable: resizeLast
 * 
 * If the last element should be resized to fill out the parent. Default is
 * false. If <resizeParent> is true then this is ignored.
 */
mxStackLayout.prototype.resizeLast = false;

/**
 * Variable: wrap
 * 
 * Value at which a new column or row should be created. Default is null.
 */
mxStackLayout.prototype.wrap = null;

/**
 * Variable: borderCollapse
 * 
 * If the strokeWidth should be ignored. Default is true.
 */
mxStackLayout.prototype.borderCollapse = true;

/**
 * Variable: allowGaps
 * 
 * If gaps should be allowed in the stack. Default is false.
 */
mxStackLayout.prototype.allowGaps = false;

/**
 * Variable: gridSize
 * 
 * Grid size for alignment of position and size. Default is 0.
 */
mxStackLayout.prototype.gridSize = 0;

/**
 * Function: isHorizontal
 * 
 * Returns <horizontal>.
 */
mxStackLayout.prototype.isHorizontal = function()
{
\treturn this.horizontal;
};

/**
 * Function: moveCell
 * 
 * Implements <mxGraphLayout.moveCell>.
 */
mxStackLayout.prototype.moveCell = function(cell, x, y)
{
\tvar model = this.graph.getModel();
\tvar parent = model.getParent(cell);
\tvar horizontal = this.isHorizontal();
\t
\tif (cell != null && parent != null)
\t{
\t\tvar i = 0;
\t\tvar last = 0;
\t\tvar childCount = model.getChildCount(parent);
\t\tvar value = (horizontal) ? x : y;
\t\tvar pstate = this.graph.getView().getState(parent);

\t\tif (pstate != null)
\t\t{
\t\t\tvalue -= (horizontal) ? pstate.x : pstate.y;
\t\t}
\t\t
\t\tvalue /= this.graph.view.scale;
\t\t
\t\tfor (i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(parent, i);
\t\t\t
\t\t\tif (child != cell)
\t\t\t{
\t\t\t\tvar bounds = model.getGeometry(child);
\t\t\t\t
\t\t\t\tif (bounds != null)
\t\t\t\t{
\t\t\t\t\tvar tmp = (horizontal) ?
\t\t\t\t\t\tbounds.x + bounds.width / 2 :
\t\t\t\t\t\tbounds.y + bounds.height / 2;
\t\t\t\t\t
\t\t\t\t\tif (last <= value && tmp > value)
\t\t\t\t\t{
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tlast = tmp;
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Changes child order in parent
\t\tvar idx = parent.getIndex(cell);
\t\tidx = Math.max(0, i - ((i > idx) ? 1 : 0));

\t\tmodel.add(parent, cell, idx);
\t}
};

/**
 * Function: getParentSize
 * 
 * Returns the size for the parent container or the size of the graph
 * container if the parent is a layer or the root of the model.
 */
mxStackLayout.prototype.getParentSize = function(parent)
{
\tvar model = this.graph.getModel();\t\t\t
\tvar pgeo = model.getGeometry(parent);
\t
\t// Handles special case where the parent is either a layer with no
\t// geometry or the current root of the view in which case the size
\t// of the graph's container will be used.
\tif (this.graph.container != null && ((pgeo == null &&
\t\tmodel.isLayer(parent)) || parent == this.graph.getView().currentRoot))
\t{
\t\tvar width = this.graph.container.offsetWidth - 1;
\t\tvar height = this.graph.container.offsetHeight - 1;
\t\tpgeo = new mxRectangle(0, 0, width, height);
\t}
\t
\treturn pgeo;
};

/**
 * Function: getLayoutCells
 * 
 * Returns the cells to be layouted.
 */
mxStackLayout.prototype.getLayoutCells = function(parent)
{
\tvar model = this.graph.getModel();
\tvar childCount = model.getChildCount(parent);
\tvar cells = [];
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(parent, i);
\t\t
\t\tif (!this.isVertexIgnored(child) && this.isVertexMovable(child))
\t\t{
\t\t\tcells.push(child);
\t\t}
\t}
\t
\tif (this.allowGaps)
\t{
\t\tcells.sort(mxUtils.bind(this, function(c1, c2)
\t\t{
\t\t\tvar geo1 = this.graph.getCellGeometry(c1);
\t\t\tvar geo2 = this.graph.getCellGeometry(c2);
\t\t\t
\t\t\treturn (this.horizontal) ?
\t\t\t\t((geo1.x == geo2.x) ? 0 : ((geo1.x > geo2.x > 0) ? 1 : -1)) :
\t\t\t\t((geo1.y == geo2.y) ? 0 : ((geo1.y > geo2.y > 0) ? 1 : -1));
\t\t}));
\t}
\t
\treturn cells;
};

/**
 * Function: snap
 * 
 * Snaps the given value to the grid size.
 */
mxStackLayout.prototype.snap = function(value)
{
\tif (this.gridSize != null && this.gridSize > 0)
\t{
\t\tvalue = Math.max(value, this.gridSize);
\t\t
\t\tif (value / this.gridSize > 1)
\t\t{
\t\t\tvar mod = value % this.gridSize;
\t\t\tvalue += mod > this.gridSize / 2 ? (this.gridSize - mod) : -mod;
\t\t}
\t}
\t
\treturn value;
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 * 
 * Only children where <isVertexIgnored> returns false are taken into
 * account.
 */
mxStackLayout.prototype.execute = function(parent)
{
\tif (parent != null)
\t{
\t\tvar pgeo = this.getParentSize(parent);
\t\tvar horizontal = this.isHorizontal();
\t\tvar model = this.graph.getModel();\t
\t\tvar fillValue = null;
\t\t
\t\tif (pgeo != null)
\t\t{
\t\t\tfillValue = (horizontal) ? pgeo.height - this.marginTop - this.marginBottom :
\t\t\t\tpgeo.width - this.marginLeft - this.marginRight;
\t\t}
\t\t
\t\tfillValue -= 2 * this.border;
\t\tvar x0 = this.x0 + this.border + this.marginLeft;
\t\tvar y0 = this.y0 + this.border + this.marginTop;
\t\t
\t\t// Handles swimlane start size
\t\tif (this.graph.isSwimlane(parent))
\t\t{
\t\t\t// Uses computed style to get latest 
\t\t\tvar style = this.graph.getCellStyle(parent);
\t\t\tvar start = mxUtils.getNumber(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE);
\t\t\tvar horz = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true) == 1;

\t\t\tif (pgeo != null)
\t\t\t{
\t\t\t\tif (horz)
\t\t\t\t{
\t\t\t\t\tstart = Math.min(start, pgeo.height);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tstart = Math.min(start, pgeo.width);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (horizontal == horz)
\t\t\t{
\t\t\t\tfillValue -= start;
\t\t\t}

\t\t\tif (horz)
\t\t\t{
\t\t\t\ty0 += start;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tx0 += start;
\t\t\t}
\t\t}

\t\tmodel.beginUpdate();
\t\ttry
\t\t{
\t\t\tvar tmp = 0;
\t\t\tvar last = null;
\t\t\tvar lastValue = 0;
\t\t\tvar lastChild = null;
\t\t\tvar cells = this.getLayoutCells(parent);
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar child = cells[i];
\t\t\t\tvar geo = model.getGeometry(child);
\t\t\t\t
\t\t\t\tif (geo != null)
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t
\t\t\t\t\tif (this.wrap != null && last != null)
\t\t\t\t\t{
\t\t\t\t\t\tif ((horizontal && last.x + last.width +
\t\t\t\t\t\t\tgeo.width + 2 * this.spacing > this.wrap) ||
\t\t\t\t\t\t\t(!horizontal && last.y + last.height +
\t\t\t\t\t\t\tgeo.height + 2 * this.spacing > this.wrap))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tlast = null;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (horizontal)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\ty0 += tmp + this.spacing;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tx0 += tmp + this.spacing;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\ttmp = 0;
\t\t\t\t\t\t}\t
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\ttmp = Math.max(tmp, (horizontal) ? geo.height : geo.width);
\t\t\t\t\tvar sw = 0;
\t\t\t\t\t
\t\t\t\t\tif (!this.borderCollapse)
\t\t\t\t\t{
\t\t\t\t\t\tvar childStyle = this.graph.getCellStyle(child);
\t\t\t\t\t\tsw = mxUtils.getNumber(childStyle, mxConstants.STYLE_STROKEWIDTH, 1);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (last != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar temp = lastValue + this.spacing + Math.floor(sw / 2);
\t\t\t\t\t\t
\t\t\t\t\t\tif (horizontal)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.x = this.snap(((this.allowGaps) ? Math.max(temp, geo.x) :
\t\t\t\t\t\t\t\ttemp) - this.marginLeft) + this.marginLeft;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.y = this.snap(((this.allowGaps) ? Math.max(temp, geo.y) :
\t\t\t\t\t\t\t\ttemp) - this.marginTop) + this.marginTop;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse if (!this.keepFirstLocation)
\t\t\t\t\t{
\t\t\t\t\t\tif (horizontal)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.x = (this.allowGaps && geo.x > x0) ? Math.max(this.snap(geo.x -
\t\t\t\t\t\t\t\tthis.marginLeft) + this.marginLeft, x0) : x0;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.y = (this.allowGaps && geo.y > y0) ? Math.max(this.snap(geo.y -
\t\t\t\t\t\t\t\tthis.marginTop) + this.marginTop, y0) : y0;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (horizontal)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.y = y0;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tgeo.x = x0;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (this.fill && fillValue != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (horizontal)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.height = fillValue;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.width = fillValue;\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (horizontal)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.width = this.snap(geo.width);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tgeo.height = this.snap(geo.height);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tthis.setChildGeometry(child, geo);
\t\t\t\t\tlastChild = child;
\t\t\t\t\tlast = geo;
\t\t\t\t\t
\t\t\t\t\tif (horizontal)
\t\t\t\t\t{
\t\t\t\t\t\tlastValue = last.x + last.width + Math.floor(sw / 2);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tlastValue = last.y + last.height + Math.floor(sw / 2);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tif (this.resizeParent && pgeo != null && last != null && !this.graph.isCellCollapsed(parent))
\t\t\t{
\t\t\t\tthis.updateParentGeometry(parent, pgeo, last);
\t\t\t}
\t\t\telse if (this.resizeLast && pgeo != null && last != null && lastChild != null)
\t\t\t{
\t\t\t\tif (horizontal)
\t\t\t\t{
\t\t\t\t\tlast.width = pgeo.width - last.x - this.spacing - this.marginRight - this.marginLeft;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tlast.height = pgeo.height - last.y - this.spacing - this.marginBottom;
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.setChildGeometry(lastChild, last);
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t}
};

/**
 * Function: setChildGeometry
 * 
 * Sets the specific geometry to the given child cell.
 * 
 * Parameters:
 * 
 * child - The given child of <mxCell>.
 * geo - The specific geometry of <mxGeometry>.
 */
mxStackLayout.prototype.setChildGeometry = function(child, geo)
{
\tvar geo2 = this.graph.getCellGeometry(child);
\t
\tif (geo2 == null || geo.x != geo2.x || geo.y != geo2.y ||
\t\tgeo.width != geo2.width || geo.height != geo2.height)
\t{
\t\tthis.graph.getModel().setGeometry(child, geo);
\t}
};

/**
 * Function: updateParentGeometry
 * 
 * Updates the geometry of the given parent cell.
 * 
 * Parameters:
 * 
 * parent - The given parent of <mxCell>.
 * pgeo - The new <mxGeometry> for parent.
 * last - The last <mxGeometry>.
 */
mxStackLayout.prototype.updateParentGeometry = function(parent, pgeo, last)
{
\tvar horizontal = this.isHorizontal();
\tvar model = this.graph.getModel();\t

\tvar pgeo2 = pgeo.clone();
\t
\tif (horizontal)
\t{
\t\tvar tmp = last.x + last.width + this.marginRight + this.border;
\t\t
\t\tif (this.resizeParentMax)
\t\t{
\t\t\tpgeo2.width = Math.max(pgeo2.width, tmp);
\t\t}
\t\telse
\t\t{
\t\t\tpgeo2.width = tmp;
\t\t}
\t}
\telse
\t{
\t\tvar tmp = last.y + last.height + this.marginBottom + this.border;
\t\t
\t\tif (this.resizeParentMax)
\t\t{
\t\t\tpgeo2.height = Math.max(pgeo2.height, tmp);
\t\t}
\t\telse
\t\t{
\t\t\tpgeo2.height = tmp;
\t\t}
\t}
\t
\tif (pgeo.x != pgeo2.x || pgeo.y != pgeo2.y ||
\t\tpgeo.width != pgeo2.width || pgeo.height != pgeo2.height)
\t{
\t\tmodel.setGeometry(parent, pgeo2);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPartitionLayout
 * 
 * Extends <mxGraphLayout> for partitioning the parent cell vertically or
 * horizontally by filling the complete area with the child cells. A horizontal
 * layout partitions the height of the given parent whereas a a non-horizontal
 * layout partitions the width. If the parent is a layer (that is, a child of
 * the root node), then the current graph size is partitioned. The children do
 * not need to be connected for this layout to work.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxPartitionLayout(graph, true, 10, 20);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxPartitionLayout
 * 
 * Constructs a new stack layout layout for the specified graph,
 * spacing, orientation and offset.
 */
function mxPartitionLayout(graph, horizontal, spacing, border)
{
\tmxGraphLayout.call(this, graph);
\tthis.horizontal = (horizontal != null) ? horizontal : true;
\tthis.spacing = spacing || 0;
\tthis.border = border || 0;
};

/**
 * Extends mxGraphLayout.
 */
mxPartitionLayout.prototype = new mxGraphLayout();
mxPartitionLayout.prototype.constructor = mxPartitionLayout;

/**
 * Variable: horizontal
 * 
 * Boolean indicating the direction in which the space is partitioned.
 * Default is true.
 */
mxPartitionLayout.prototype.horizontal = null;

/**
 * Variable: spacing
 * 
 * Integer that specifies the absolute spacing in pixels between the
 * children. Default is 0.
 */
mxPartitionLayout.prototype.spacing = null;

/**
 * Variable: border
 * 
 * Integer that specifies the absolute inset in pixels for the parent that
 * contains the children. Default is 0.
 */
mxPartitionLayout.prototype.border = null;

/**
 * Variable: resizeVertices
 * 
 * Boolean that specifies if vertices should be resized. Default is true.
 */
mxPartitionLayout.prototype.resizeVertices = true;

/**
 * Function: isHorizontal
 * 
 * Returns <horizontal>.
 */
mxPartitionLayout.prototype.isHorizontal = function()
{
\treturn this.horizontal;
};

/**
 * Function: moveCell
 * 
 * Implements <mxGraphLayout.moveCell>.
 */
mxPartitionLayout.prototype.moveCell = function(cell, x, y)
{
\tvar model = this.graph.getModel();
\tvar parent = model.getParent(cell);
\t
\tif (cell != null &&
\t\tparent != null)
\t{
\t\tvar i = 0;
\t\tvar last = 0;
\t\tvar childCount = model.getChildCount(parent);
\t\t
\t\t// Finds index of the closest swimlane
\t\t// TODO: Take into account the orientation
\t\tfor (i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(parent, i);
\t\t\tvar bounds = this.getVertexBounds(child);
\t\t\t
\t\t\tif (bounds != null)
\t\t\t{
\t\t\t\tvar tmp = bounds.x + bounds.width / 2;
\t\t\t\t
\t\t\t\tif (last < x && tmp > x)
\t\t\t\t{
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t\t
\t\t\t\tlast = tmp;
\t\t\t}
\t\t}
\t\t
\t\t// Changes child order in parent
\t\tvar idx = parent.getIndex(cell);
\t\tidx = Math.max(0, i - ((i > idx) ? 1 : 0));
\t\t
\t\tmodel.add(parent, cell, idx);
\t}
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>. All children where <isVertexIgnored>
 * returns false and <isVertexMovable> returns true are modified.
 */
mxPartitionLayout.prototype.execute = function(parent)
{
\tvar horizontal = this.isHorizontal();
\tvar model = this.graph.getModel();
\tvar pgeo = model.getGeometry(parent);
\t
\t// Handles special case where the parent is either a layer with no
\t// geometry or the current root of the view in which case the size
\t// of the graph's container will be used.
\tif (this.graph.container != null &&
\t\t((pgeo == null &&
\t\tmodel.isLayer(parent)) ||
\t\tparent == this.graph.getView().currentRoot))
\t{
\t\tvar width = this.graph.container.offsetWidth - 1;
\t\tvar height = this.graph.container.offsetHeight - 1;
\t\tpgeo = new mxRectangle(0, 0, width, height);
\t}

\tif (pgeo != null)
\t{
\t\tvar children = [];
\t\tvar childCount = model.getChildCount(parent);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(parent, i);
\t\t\t
\t\t\tif (!this.isVertexIgnored(child) &&
\t\t\t\tthis.isVertexMovable(child))
\t\t\t{
\t\t\t\tchildren.push(child);
\t\t\t}
\t\t}
\t\t
\t\tvar n = children.length;

\t\tif (n > 0)
\t\t{
\t\t\tvar x0 = this.border;
\t\t\tvar y0 = this.border;
\t\t\tvar other = (horizontal) ? pgeo.height : pgeo.width;
\t\t\tother -= 2 * this.border;

\t\t\tvar size = (this.graph.isSwimlane(parent)) ?
\t\t\t\tthis.graph.getStartSize(parent) :
\t\t\t\tnew mxRectangle();

\t\t\tother -= (horizontal) ? size.height : size.width;
\t\t\tx0 = x0 + size.width;
\t\t\ty0 = y0 + size.height;

\t\t\tvar tmp = this.border + (n - 1) * this.spacing;
\t\t\tvar value = (horizontal) ?
\t\t\t\t((pgeo.width - x0 - tmp) / n) :
\t\t\t\t((pgeo.height - y0 - tmp) / n);
\t\t\t
\t\t\t// Avoids negative values, that is values where the sum of the
\t\t\t// spacing plus the border is larger then the available space
\t\t\tif (value > 0)
\t\t\t{
\t\t\t\tmodel.beginUpdate();
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < n; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar child = children[i];
\t\t\t\t\t\tvar geo = model.getGeometry(child);
\t\t\t\t\t
\t\t\t\t\t\tif (geo != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\tgeo.x = x0;
\t\t\t\t\t\t\tgeo.y = y0;

\t\t\t\t\t\t\tif (horizontal)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (this.resizeVertices)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tgeo.width = value;
\t\t\t\t\t\t\t\t\tgeo.height = other;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tx0 += value + this.spacing;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (this.resizeVertices)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tgeo.height = value;
\t\t\t\t\t\t\t\t\tgeo.width = other;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\ty0 += value + this.spacing;
\t\t\t\t\t\t\t}

\t\t\t\t\t\t\tmodel.setGeometry(child, geo);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tfinally
\t\t\t\t{
\t\t\t\t\tmodel.endUpdate();
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxCompactTreeLayout
 * 
 * Extends <mxGraphLayout> to implement a compact tree (Moen) algorithm. This
 * layout is suitable for graphs that have no cycles (trees). Vertices that are
 * not connected to the tree will be ignored by this layout.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxCompactTreeLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxCompactTreeLayout
 * 
 * Constructs a new compact tree layout for the specified graph
 * and orientation.
 */
function mxCompactTreeLayout(graph, horizontal, invert)
{
\tmxGraphLayout.call(this, graph);
\tthis.horizontal = (horizontal != null) ? horizontal : true;
\tthis.invert = (invert != null) ? invert : false;
};

/**
 * Extends mxGraphLayout.
 */
mxCompactTreeLayout.prototype = new mxGraphLayout();
mxCompactTreeLayout.prototype.constructor = mxCompactTreeLayout;

/**
 * Variable: horizontal
 *
 * Specifies the orientation of the layout. Default is true.
 */
mxCompactTreeLayout.prototype.horizontal = null;\t 

/**
 * Variable: invert
 *
 * Specifies if edge directions should be inverted. Default is false.
 */
mxCompactTreeLayout.prototype.invert = null;\t 

/**
 * Variable: resizeParent
 * 
 * If the parents should be resized to match the width/height of the
 * children. Default is true.
 */
mxCompactTreeLayout.prototype.resizeParent = true;

/**
 * Variable: maintainParentLocation
 * 
 * Specifies if the parent location should be maintained, so that the
 * top, left corner stays the same before and after execution of
 * the layout. Default is false for backwards compatibility.
 */
mxCompactTreeLayout.prototype.maintainParentLocation = false;

/**
 * Variable: groupPadding
 * 
 * Padding added to resized parents. Default is 10.
 */
mxCompactTreeLayout.prototype.groupPadding = 10;

/**
 * Variable: groupPaddingTop
 * 
 * Top padding added to resized parents. Default is 0.
 */
mxCompactTreeLayout.prototype.groupPaddingTop = 0;

/**
 * Variable: groupPaddingRight
 * 
 * Right padding added to resized parents. Default is 0.
 */
mxCompactTreeLayout.prototype.groupPaddingRight = 0;

/**
 * Variable: groupPaddingBottom
 * 
 * Bottom padding added to resized parents. Default is 0.
 */
mxCompactTreeLayout.prototype.groupPaddingBottom = 0;

/**
 * Variable: groupPaddingLeft
 * 
 * Left padding added to resized parents. Default is 0.
 */
mxCompactTreeLayout.prototype.groupPaddingLeft = 0;

/**
 * Variable: parentsChanged
 *
 * A set of the parents that need updating based on children
 * process as part of the layout.
 */
mxCompactTreeLayout.prototype.parentsChanged = null;

/**
 * Variable: moveTree
 * 
 * Specifies if the tree should be moved to the top, left corner
 * if it is inside a top-level layer. Default is false.
 */
mxCompactTreeLayout.prototype.moveTree = false;

/**
 * Variable: visited
 * 
 * Specifies if the tree should be moved to the top, left corner
 * if it is inside a top-level layer. Default is false.
 */
mxCompactTreeLayout.prototype.visited = null;

/**
 * Variable: levelDistance
 *
 * Holds the levelDistance. Default is 10.
 */
mxCompactTreeLayout.prototype.levelDistance = 10;

/**
 * Variable: nodeDistance
 *
 * Holds the nodeDistance. Default is 20.
 */
mxCompactTreeLayout.prototype.nodeDistance = 20;

/**
 * Variable: resetEdges
 * 
 * Specifies if all edge points of traversed edges should be removed.
 * Default is true.
 */
mxCompactTreeLayout.prototype.resetEdges = true;

/**
 * Variable: prefHozEdgeSep
 * 
 * The preferred horizontal distance between edges exiting a vertex.
 */
mxCompactTreeLayout.prototype.prefHozEdgeSep = 5;

/**
 * Variable: prefVertEdgeOff
 * 
 * The preferred vertical offset between edges exiting a vertex.
 */
mxCompactTreeLayout.prototype.prefVertEdgeOff = 4;

/**
 * Variable: minEdgeJetty
 * 
 * The minimum distance for an edge jetty from a vertex.
 */
mxCompactTreeLayout.prototype.minEdgeJetty = 8;

/**
 * Variable: channelBuffer
 * 
 * The size of the vertical buffer in the center of inter-rank channels
 * where edge control points should not be placed.
 */
mxCompactTreeLayout.prototype.channelBuffer = 4;

/**
 * Variable: edgeRouting
 * 
 * Whether or not to apply the internal tree edge routing.
 */
mxCompactTreeLayout.prototype.edgeRouting = true;

/**
 * Variable: sortEdges
 * 
 * Specifies if edges should be sorted according to the order of their
 * opposite terminal cell in the model.
 */
mxCompactTreeLayout.prototype.sortEdges = false;

/**
 * Variable: alignRanks
 * 
 * Whether or not the tops of cells in each rank should be aligned
 * across the rank
 */
mxCompactTreeLayout.prototype.alignRanks = false;

/**
 * Variable: maxRankHeight
 * 
 * An array of the maximum height of cells (relative to the layout direction)
 * per rank
 */
mxCompactTreeLayout.prototype.maxRankHeight = null;

/**
 * Variable: root
 * 
 * The cell to use as the root of the tree
 */
mxCompactTreeLayout.prototype.root = null;

/**
 * Variable: node
 * 
 * The internal node representation of the root cell. Do not set directly
 * , this value is only exposed to assist with post-processing functionality
 */
mxCompactTreeLayout.prototype.node = null;

/**
 * Function: isVertexIgnored
 * 
 * Returns a boolean indicating if the given <mxCell> should be ignored as a
 * vertex. This returns true if the cell has no connections.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> whose ignored state should be returned.
 */
mxCompactTreeLayout.prototype.isVertexIgnored = function(vertex)
{
\treturn mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
\t\tthis.graph.getConnections(vertex).length == 0;
};

/**
 * Function: isHorizontal
 * 
 * Returns <horizontal>.
 */
mxCompactTreeLayout.prototype.isHorizontal = function()
{
\treturn this.horizontal;
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 * 
 * If the parent has any connected edges, then it is used as the root of
 * the tree. Else, <mxGraph.findTreeRoots> will be used to find a suitable
 * root node within the set of children of the given parent.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be laid out.
 * root - Optional <mxCell> that will be used as the root of the tree.
 * Overrides <root> if specified.
 */
mxCompactTreeLayout.prototype.execute = function(parent, root)
{
\tthis.parent = parent;
\tvar model = this.graph.getModel();

\tif (root == null)
\t{
\t\t// Takes the parent as the root if it has outgoing edges
\t\tif (this.graph.getEdges(parent, model.getParent(parent),
\t\t\tthis.invert, !this.invert, false).length > 0)
\t\t{
\t\t\tthis.root = parent;
\t\t}
\t\t
\t\t// Tries to find a suitable root in the parent's
\t\t// children
\t\telse
\t\t{
\t\t\tvar roots = this.graph.findTreeRoots(parent, true, this.invert);
\t\t\t
\t\t\tif (roots.length > 0)
\t\t\t{
\t\t\t\tfor (var i = 0; i < roots.length; i++)
\t\t\t\t{
\t\t\t\t\tif (!this.isVertexIgnored(roots[i]) &&
\t\t\t\t\t\tthis.graph.getEdges(roots[i], null,
\t\t\t\t\t\t\tthis.invert, !this.invert, false).length > 0)
\t\t\t\t\t{
\t\t\t\t\t\tthis.root = roots[i];
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tthis.root = root;
\t}
\t
\tif (this.root != null)
\t{
\t\tif (this.resizeParent)
\t\t{
\t\t\tthis.parentsChanged = new Object();
\t\t}
\t\telse
\t\t{
\t\t\tthis.parentsChanged = null;
\t\t}

\t\t//  Maintaining parent location
\t\tthis.parentX = null;
\t\tthis.parentY = null;
\t\t
\t\tif (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
\t\t{
\t\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tthis.parentX = geo.x;
\t\t\t\tthis.parentY = geo.y;
\t\t\t}
\t\t}
\t\t
\t\tmodel.beginUpdate();
\t\t
\t\ttry
\t\t{
\t\t\tthis.visited = new Object();
\t\t\tthis.node = this.dfs(this.root, parent);
\t\t\t
\t\t\tif (this.alignRanks)
\t\t\t{
\t\t\t\tthis.maxRankHeight = [];
\t\t\t\tthis.findRankHeights(this.node, 0);
\t\t\t\tthis.setCellHeights(this.node, 0);
\t\t\t}
\t\t\t
\t\t\tif (this.node != null)
\t\t\t{
\t\t\t\tthis.layout(this.node);
\t\t\t\tvar x0 = this.graph.gridSize;
\t\t\t\tvar y0 = x0;
\t\t\t\t
\t\t\t\tif (!this.moveTree)
\t\t\t\t{
\t\t\t\t\tvar g = this.getVertexBounds(this.root);
\t\t\t\t\t
\t\t\t\t\tif (g != null)
\t\t\t\t\t{
\t\t\t\t\t\tx0 = g.x;
\t\t\t\t\t\ty0 = g.y;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar bounds = null;
\t\t\t\t
\t\t\t\tif (this.isHorizontal())
\t\t\t\t{
\t\t\t\t\tbounds = this.horizontalLayout(this.node, x0, y0);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tbounds = this.verticalLayout(this.node, null, x0, y0);
\t\t\t\t}

\t\t\t\tif (bounds != null)
\t\t\t\t{
\t\t\t\t\tvar dx = 0;
\t\t\t\t\tvar dy = 0;

\t\t\t\t\tif (bounds.x < 0)
\t\t\t\t\t{
\t\t\t\t\t\tdx = Math.abs(x0 - bounds.x);
\t\t\t\t\t}

\t\t\t\t\tif (bounds.y < 0)
\t\t\t\t\t{
\t\t\t\t\t\tdy = Math.abs(y0 - bounds.y);\t
\t\t\t\t\t}

\t\t\t\t\tif (dx != 0 || dy != 0)
\t\t\t\t\t{
\t\t\t\t\t\tthis.moveNode(this.node, dx, dy);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (this.resizeParent)
\t\t\t\t\t{
\t\t\t\t\t\tthis.adjustParents();
\t\t\t\t\t}

\t\t\t\t\tif (this.edgeRouting)
\t\t\t\t\t{
\t\t\t\t\t\t// Iterate through all edges setting their positions
\t\t\t\t\t\tthis.localEdgeProcessing(this.node);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Maintaining parent location
\t\t\t\tif (this.parentX != null && this.parentY != null)
\t\t\t\t{
\t\t\t\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t\t\t\t
\t\t\t\t\tif (geo != null)
\t\t\t\t\t{
\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\tgeo.x = this.parentX;
\t\t\t\t\t\tgeo.y = this.parentY;
\t\t\t\t\t\tmodel.setGeometry(parent, geo);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t}
};

/**
 * Function: moveNode
 * 
 * Moves the specified node and all of its children by the given amount.
 */
mxCompactTreeLayout.prototype.moveNode = function(node, dx, dy)
{
\tnode.x += dx;
\tnode.y += dy;
\tthis.apply(node);
\t
\tvar child = node.child;
\t
\twhile (child != null)
\t{
\t\tthis.moveNode(child, dx, dy);
\t\tchild = child.next;
\t}
};


/**
 * Function: sortOutgoingEdges
 * 
 * Called if <sortEdges> is true to sort the array of outgoing edges in place.
 */
mxCompactTreeLayout.prototype.sortOutgoingEdges = function(source, edges)
{
\tvar lookup = new mxDictionary();
\t
\tedges.sort(function(e1, e2)
\t{
\t\tvar end1 = e1.getTerminal(e1.getTerminal(false) == source);
\t\tvar p1 = lookup.get(end1);
\t\t
\t\tif (p1 == null)
\t\t{
\t\t\tp1 = mxCellPath.create(end1).split(mxCellPath.PATH_SEPARATOR);
\t\t\tlookup.put(end1, p1);
\t\t}

\t\tvar end2 = e2.getTerminal(e2.getTerminal(false) == source);
\t\tvar p2 = lookup.get(end2);
\t\t
\t\tif (p2 == null)
\t\t{
\t\t\tp2 = mxCellPath.create(end2).split(mxCellPath.PATH_SEPARATOR);
\t\t\tlookup.put(end2, p2);
\t\t}

\t\treturn mxCellPath.compare(p1, p2);
\t});
};

/**
 * Function: findRankHeights
 * 
 * Stores the maximum height (relative to the layout
 * direction) of cells in each rank
 */
mxCompactTreeLayout.prototype.findRankHeights = function(node, rank)
{
\tif (this.maxRankHeight[rank] == null || this.maxRankHeight[rank] < node.height)
\t{
\t\tthis.maxRankHeight[rank] = node.height;
\t}

\tvar child = node.child;
\t
\twhile (child != null)
\t{
\t\tthis.findRankHeights(child, rank + 1);
\t\tchild = child.next;
\t}
};

/**
 * Function: setCellHeights
 * 
 * Set the cells heights (relative to the layout
 * direction) when the tops of each rank are to be aligned
 */
mxCompactTreeLayout.prototype.setCellHeights = function(node, rank)
{
\tif (this.maxRankHeight[rank] != null && this.maxRankHeight[rank] > node.height)
\t{
\t\tnode.height = this.maxRankHeight[rank];
\t}

\tvar child = node.child;
\t
\twhile (child != null)
\t{
\t\tthis.setCellHeights(child, rank + 1);
\t\tchild = child.next;
\t}
};

/**
 * Function: dfs
 * 
 * Does a depth first search starting at the specified cell.
 * Makes sure the specified parent is never left by the
 * algorithm.
 */
mxCompactTreeLayout.prototype.dfs = function(cell, parent)
{
\tvar id = mxCellPath.create(cell);
\tvar node = null;
\t
\tif (cell != null && this.visited[id] == null && !this.isVertexIgnored(cell))
\t{
\t\tthis.visited[id] = cell;
\t\tnode = this.createNode(cell);

\t\tvar model = this.graph.getModel();
\t\tvar prev = null;
\t\tvar out = this.graph.getEdges(cell, parent, this.invert, !this.invert, false, true);
\t\tvar view = this.graph.getView();
\t\t
\t\tif (this.sortEdges)
\t\t{
\t\t\tthis.sortOutgoingEdges(cell, out);
\t\t}

\t\tfor (var i = 0; i < out.length; i++)
\t\t{
\t\t\tvar edge = out[i];
\t\t\t
\t\t\tif (!this.isEdgeIgnored(edge))
\t\t\t{
\t\t\t\t// Resets the points on the traversed edge
\t\t\t\tif (this.resetEdges)
\t\t\t\t{
\t\t\t\t\tthis.setEdgePoints(edge, null);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (this.edgeRouting)
\t\t\t\t{
\t\t\t\t\tthis.setEdgeStyleEnabled(edge, false);
\t\t\t\t\tthis.setEdgePoints(edge, null);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Checks if terminal in same swimlane
\t\t\t\tvar state = view.getState(edge);
\t\t\t\tvar target = (state != null) ? state.getVisibleTerminal(this.invert) : view.getVisibleTerminal(edge, this.invert);
\t\t\t\tvar tmp = this.dfs(target, parent);
\t\t\t\t
\t\t\t\tif (tmp != null && model.getGeometry(target) != null)
\t\t\t\t{
\t\t\t\t\tif (prev == null)
\t\t\t\t\t{
\t\t\t\t\t\tnode.child = tmp;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tprev.next = tmp;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tprev = tmp;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn node;
};

/**
 * Function: layout
 * 
 * Starts the actual compact tree layout algorithm
 * at the given node.
 */
mxCompactTreeLayout.prototype.layout = function(node)
{
\tif (node != null)
\t{
\t\tvar child = node.child;
\t\t
\t\twhile (child != null)
\t\t{
\t\t\tthis.layout(child);
\t\t\tchild = child.next;
\t\t}
\t\t
\t\tif (node.child != null)
\t\t{
\t\t\tthis.attachParent(node, this.join(node));
\t\t}
\t\telse
\t\t{
\t\t\tthis.layoutLeaf(node);
\t\t}
\t}
};

/**
 * Function: horizontalLayout
 */
mxCompactTreeLayout.prototype.horizontalLayout = function(node, x0, y0, bounds)
{
\tnode.x += x0 + node.offsetX;
\tnode.y += y0 + node.offsetY;
\tbounds = this.apply(node, bounds);
\tvar child = node.child;
\t
\tif (child != null)
\t{
\t\tbounds = this.horizontalLayout(child, node.x, node.y, bounds);
\t\tvar siblingOffset = node.y + child.offsetY;
\t\tvar s = child.next;
\t\t
\t\twhile (s != null)
\t\t{
\t\t\tbounds = this.horizontalLayout(s, node.x + child.offsetX, siblingOffset, bounds);
\t\t\tsiblingOffset += s.offsetY;
\t\t\ts = s.next;
\t\t}
\t}
\t
\treturn bounds;
};
\t
/**
 * Function: verticalLayout
 */
mxCompactTreeLayout.prototype.verticalLayout = function(node, parent, x0, y0, bounds)
{
\tnode.x += x0 + node.offsetY;
\tnode.y += y0 + node.offsetX;
\tbounds = this.apply(node, bounds);
\tvar child = node.child;
\t
\tif (child != null)
\t{
\t\tbounds = this.verticalLayout(child, node, node.x, node.y, bounds);
\t\tvar siblingOffset = node.x + child.offsetY;
\t\tvar s = child.next;
\t\t
\t\twhile (s != null)
\t\t{
\t\t\tbounds = this.verticalLayout(s, node, siblingOffset, node.y + child.offsetX, bounds);
\t\t\tsiblingOffset += s.offsetY;
\t\t\ts = s.next;
\t\t}
\t}
\t
\treturn bounds;
};

/**
 * Function: attachParent
 */
mxCompactTreeLayout.prototype.attachParent = function(node, height)
{
\tvar x = this.nodeDistance + this.levelDistance;
\tvar y2 = (height - node.width) / 2 - this.nodeDistance;
\tvar y1 = y2 + node.width + 2 * this.nodeDistance - height;
\t
\tnode.child.offsetX = x + node.height;
\tnode.child.offsetY = y1;
\t
\tnode.contour.upperHead = this.createLine(node.height, 0,
\t\tthis.createLine(x, y1, node.contour.upperHead));
\tnode.contour.lowerHead = this.createLine(node.height, 0,
\t\tthis.createLine(x, y2, node.contour.lowerHead));
};

/**
 * Function: layoutLeaf
 */
mxCompactTreeLayout.prototype.layoutLeaf = function(node)
{
\tvar dist = 2 * this.nodeDistance;
\t
\tnode.contour.upperTail = this.createLine(
\t\tnode.height + dist, 0);
\tnode.contour.upperHead = node.contour.upperTail;
\tnode.contour.lowerTail = this.createLine(
\t\t0, -node.width - dist);
\tnode.contour.lowerHead = this.createLine(
\t\tnode.height + dist, 0, node.contour.lowerTail);
};

/**
 * Function: join
 */
mxCompactTreeLayout.prototype.join = function(node)
{
\tvar dist = 2 * this.nodeDistance;
\t
\tvar child = node.child;
\tnode.contour = child.contour;
\tvar h = child.width + dist;
\tvar sum = h;
\tchild = child.next;
\t
\twhile (child != null)
\t{
\t\tvar d = this.merge(node.contour, child.contour);
\t\tchild.offsetY = d + h;
\t\tchild.offsetX = 0;
\t\th = child.width + dist;
\t\tsum += d + h;
\t\tchild = child.next;
\t}
\t
\treturn sum;
};

/**
 * Function: merge
 */
mxCompactTreeLayout.prototype.merge = function(p1, p2)
{
\tvar x = 0;
\tvar y = 0;
\tvar total = 0;
\t
\tvar upper = p1.lowerHead;
\tvar lower = p2.upperHead;
\t
\twhile (lower != null && upper != null)
\t{
\t\tvar d = this.offset(x, y, lower.dx, lower.dy,
\t\t\tupper.dx, upper.dy);
\t\ty += d;
\t\ttotal += d;
\t\t
\t\tif (x + lower.dx <= upper.dx)
\t\t{
\t\t\tx += lower.dx;
\t\t\ty += lower.dy;
\t\t\tlower = lower.next;
\t\t}
\t\telse
\t\t{\t\t\t\t
\t\t\tx -= upper.dx;
\t\t\ty -= upper.dy;
\t\t\tupper = upper.next;
\t\t}
\t}
\t
\tif (lower != null)
\t{
\t\tvar b = this.bridge(p1.upperTail, 0, 0, lower, x, y);
\t\tp1.upperTail = (b.next != null) ? p2.upperTail : b;
\t\tp1.lowerTail = p2.lowerTail;
\t}
\telse
\t{
\t\tvar b = this.bridge(p2.lowerTail, x, y, upper, 0, 0);
\t\t
\t\tif (b.next == null)
\t\t{
\t\t\tp1.lowerTail = b;
\t\t}
\t}
\t
\tp1.lowerHead = p2.lowerHead;
\t
\treturn total;
};

/**
 * Function: offset
 */
mxCompactTreeLayout.prototype.offset = function(p1, p2, a1, a2, b1, b2)
{
\tvar d = 0;
\t
\tif (b1 <= p1 || p1 + a1 <= 0)
\t{
\t\treturn 0;
\t}

\tvar t = b1 * a2 - a1 * b2;
\t
\tif (t > 0)
\t{
\t\tif (p1 < 0)
\t\t{
\t\t\tvar s = p1 * a2;
\t\t\td = s / a1 - p2;
\t\t}
\t\telse if (p1 > 0)
\t\t{
\t\t\tvar s = p1 * b2;
\t\t\td = s / b1 - p2;
\t\t}
\t\telse
\t\t{
\t\t\td = -p2;
\t\t}
\t}
\telse if (b1 < p1 + a1)
\t{
\t\tvar s = (b1 - p1) * a2;
\t\td = b2 - (p2 + s / a1);
\t}
\telse if (b1 > p1 + a1)
\t{
\t\tvar s = (a1 + p1) * b2;
\t\td = s / b1 - (p2 + a2);
\t}
\telse
\t{
\t\td = b2 - (p2 + a2);
\t}

\tif (d > 0)
\t{
\t\treturn d;
\t}
\telse
\t{
\t\treturn 0;
\t}
};

/**
 * Function: bridge
 */
mxCompactTreeLayout.prototype.bridge = function(line1, x1, y1, line2, x2, y2)
{
\tvar dx = x2 + line2.dx - x1;
\tvar dy = 0;
\tvar s = 0;
\t
\tif (line2.dx == 0)
\t{
\t\tdy = line2.dy;
\t}
\telse
\t{
\t\ts = dx * line2.dy;
\t\tdy = s / line2.dx;
\t}
\t
\tvar r = this.createLine(dx, dy, line2.next);
\tline1.next = this.createLine(0, y2 + line2.dy - dy - y1, r);
\t
\treturn r;
};

/**
 * Function: createNode
 */
mxCompactTreeLayout.prototype.createNode = function(cell)
{
\tvar node = new Object();
\tnode.cell = cell;
\tnode.x = 0;
\tnode.y = 0;
\tnode.width = 0;
\tnode.height = 0;
\t
\tvar geo = this.getVertexBounds(cell);
\t
\tif (geo != null)
\t{
\t\tif (this.isHorizontal())
\t\t{
\t\t\tnode.width = geo.height;
\t\t\tnode.height = geo.width;\t\t\t
\t\t}
\t\telse
\t\t{
\t\t\tnode.width = geo.width;
\t\t\tnode.height = geo.height;
\t\t}
\t}
\t
\tnode.offsetX = 0;
\tnode.offsetY = 0;
\tnode.contour = new Object();
\t
\treturn node;
};

/**
 * Function: apply
 */
mxCompactTreeLayout.prototype.apply = function(node, bounds)
{
\tvar model = this.graph.getModel();
\tvar cell = node.cell;
\tvar g = model.getGeometry(cell);

\tif (cell != null && g != null)
\t{
\t\tif (this.isVertexMovable(cell))
\t\t{
\t\t\tg = this.setVertexLocation(cell, node.x, node.y);
\t\t\t
\t\t\tif (this.resizeParent)
\t\t\t{
\t\t\t\tvar parent = model.getParent(cell);
\t\t\t\tvar id = mxCellPath.create(parent);
\t\t\t\t
\t\t\t\t// Implements set semantic
\t\t\t\tif (this.parentsChanged[id] == null)
\t\t\t\t{
\t\t\t\t\tthis.parentsChanged[id] = parent;\t\t\t\t\t
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (bounds == null)
\t\t{
\t\t\tbounds = new mxRectangle(g.x, g.y, g.width, g.height);
\t\t}
\t\telse
\t\t{
\t\t\tbounds = new mxRectangle(Math.min(bounds.x, g.x),
\t\t\t\tMath.min(bounds.y, g.y),
\t\t\t\tMath.max(bounds.x + bounds.width, g.x + g.width),
\t\t\t\tMath.max(bounds.y + bounds.height, g.y + g.height));
\t\t}
\t}
\t
\treturn bounds;
};

/**
 * Function: createLine
 */
mxCompactTreeLayout.prototype.createLine = function(dx, dy, next)
{
\tvar line = new Object();
\tline.dx = dx;
\tline.dy = dy;
\tline.next = next;
\t
\treturn line;
};

/**
 * Function: adjustParents
 * 
 * Adjust parent cells whose child geometries have changed. The default 
 * implementation adjusts the group to just fit around the children with 
 * a padding.
 */
mxCompactTreeLayout.prototype.adjustParents = function()
{
\tvar tmp = [];
\t
\tfor (var id in this.parentsChanged)
\t{
\t\ttmp.push(this.parentsChanged[id]);
\t}
\t
\tthis.arrangeGroups(mxUtils.sortCells(tmp, true), this.groupPadding, this.groupPaddingTop,
\t\tthis.groupPaddingRight, this.groupPaddingBottom, this.groupPaddingLeft);
};

/**
 * Function: localEdgeProcessing
 *
 * Moves the specified node and all of its children by the given amount.
 */
mxCompactTreeLayout.prototype.localEdgeProcessing = function(node)
{
\tthis.processNodeOutgoing(node);
\tvar child = node.child;

\twhile (child != null)
\t{
\t\tthis.localEdgeProcessing(child);
\t\tchild = child.next;
\t}
};

/**
 * Function: processNodeOutgoing
 *
 * Separates the x position of edges as they connect to vertices
 */
mxCompactTreeLayout.prototype.processNodeOutgoing = function(node)
{
\tvar child = node.child;
\tvar parentCell = node.cell;

\tvar childCount = 0;
\tvar sortedCells = [];

\twhile (child != null)
\t{
\t\tchildCount++;

\t\tvar sortingCriterion = child.x;

\t\tif (this.horizontal)
\t\t{
\t\t\tsortingCriterion = child.y;
\t\t}

\t\tsortedCells.push(new WeightedCellSorter(child, sortingCriterion));
\t\tchild = child.next;
\t}

\tsortedCells.sort(WeightedCellSorter.prototype.compare);

\tvar availableWidth = node.width;

\tvar requiredWidth = (childCount + 1) * this.prefHozEdgeSep;

\t// Add a buffer on the edges of the vertex if the edge count allows
\tif (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep))
\t{
\t\tavailableWidth -= 2 * this.prefHozEdgeSep;
\t}

\tvar edgeSpacing = availableWidth / childCount;

\tvar currentXOffset = edgeSpacing / 2.0;

\tif (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep))
\t{
\t\tcurrentXOffset += this.prefHozEdgeSep;
\t}

\tvar currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff;
\tvar maxYOffset = 0;

\tvar parentBounds = this.getVertexBounds(parentCell);
\tchild = node.child;

\tfor (var j = 0; j < sortedCells.length; j++)
\t{
\t\tvar childCell = sortedCells[j].cell.cell;
\t\tvar childBounds = this.getVertexBounds(childCell);

\t\tvar edges = this.graph.getEdgesBetween(parentCell,
\t\t\t\tchildCell, false);
\t\t
\t\tvar newPoints = [];
\t\tvar x = 0;
\t\tvar y = 0;

\t\tfor (var i = 0; i < edges.length; i++)
\t\t{
\t\t\tif (this.horizontal)
\t\t\t{
\t\t\t\t// Use opposite co-ords, calculation was done for 
\t\t\t\t// 
\t\t\t\tx = parentBounds.x + parentBounds.width;
\t\t\t\ty = parentBounds.y + currentXOffset;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\tx = parentBounds.x + parentBounds.width
\t\t\t\t\t\t+ currentYOffset;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\ty = childBounds.y + childBounds.height / 2.0;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\tthis.setEdgePoints(edges[i], newPoints);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tx = parentBounds.x + currentXOffset;
\t\t\t\ty = parentBounds.y + parentBounds.height;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\ty = parentBounds.y + parentBounds.height
\t\t\t\t\t\t+ currentYOffset;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\tx = childBounds.x + childBounds.width / 2.0;
\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\tthis.setEdgePoints(edges[i], newPoints);
\t\t\t}
\t\t}

\t\tif (j < childCount / 2)
\t\t{
\t\t\tcurrentYOffset += this.prefVertEdgeOff;
\t\t}
\t\telse if (j > childCount / 2)
\t\t{
\t\t\tcurrentYOffset -= this.prefVertEdgeOff;
\t\t}
\t\t// Ignore the case if equals, this means the second of 2
\t\t// jettys with the same y (even number of edges)

\t\t//\t\t\t\t\t\t\t\tpos[k * 2] = currentX;
\t\tcurrentXOffset += edgeSpacing;
\t\t//\t\t\t\t\t\t\t\tpos[k * 2 + 1] = currentYOffset;

\t\tmaxYOffset = Math.max(maxYOffset, currentYOffset);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxRadialTreeLayout
 * 
 * Extends <mxGraphLayout> to implement a radial tree algorithm. This
 * layout is suitable for graphs that have no cycles (trees). Vertices that are
 * not connected to the tree will be ignored by this layout.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxRadialTreeLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxRadialTreeLayout
 * 
 * Constructs a new radial tree layout for the specified graph
 */
function mxRadialTreeLayout(graph)
{
\tmxCompactTreeLayout.call(this, graph , false);
};

/**
 * Extends mxGraphLayout.
 */
mxUtils.extend(mxRadialTreeLayout, mxCompactTreeLayout);

/**
 * Variable: angleOffset
 *
 * The initial offset to compute the angle position.
 */
mxRadialTreeLayout.prototype.angleOffset = 0.5;

/**
 * Variable: rootx
 *
 * The X co-ordinate of the root cell
 */
mxRadialTreeLayout.prototype.rootx = 0;

/**
 * Variable: rooty
 *
 * The Y co-ordinate of the root cell
 */
mxRadialTreeLayout.prototype.rooty = 0;

/**
 * Variable: levelDistance
 *
 * Holds the levelDistance. Default is 120.
 */
mxRadialTreeLayout.prototype.levelDistance = 120;

/**
 * Variable: nodeDistance
 *
 * Holds the nodeDistance. Default is 10.
 */
mxRadialTreeLayout.prototype.nodeDistance = 10;

/**
 * Variable: autoRadius
 * 
 * Specifies if the radios should be computed automatically
 */
mxRadialTreeLayout.prototype.autoRadius = false;

/**
 * Variable: sortEdges
 * 
 * Specifies if edges should be sorted according to the order of their
 * opposite terminal cell in the model.
 */
mxRadialTreeLayout.prototype.sortEdges = false;

/**
 * Variable: rowMinX
 * 
 * Array of leftmost x coordinate of each row
 */
mxRadialTreeLayout.prototype.rowMinX = [];

/**
 * Variable: rowMaxX
 * 
 * Array of rightmost x coordinate of each row
 */
mxRadialTreeLayout.prototype.rowMaxX = [];

/**
 * Variable: rowMinCenX
 * 
 * Array of x coordinate of leftmost vertex of each row
 */
mxRadialTreeLayout.prototype.rowMinCenX = [];

/**
 * Variable: rowMaxCenX
 * 
 * Array of x coordinate of rightmost vertex of each row
 */
mxRadialTreeLayout.prototype.rowMaxCenX = [];

/**
 * Variable: rowRadi
 * 
 * Array of y deltas of each row behind root vertex, also the radius in the tree
 */
mxRadialTreeLayout.prototype.rowRadi = [];

/**
 * Variable: row
 * 
 * Array of vertices on each row
 */
mxRadialTreeLayout.prototype.row = [];

/**
 * Function: isVertexIgnored
 * 
 * Returns a boolean indicating if the given <mxCell> should be ignored as a
 * vertex. This returns true if the cell has no connections.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> whose ignored state should be returned.
 */
mxRadialTreeLayout.prototype.isVertexIgnored = function(vertex)
{
\treturn mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
\t\tthis.graph.getConnections(vertex).length == 0;
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 * 
 * If the parent has any connected edges, then it is used as the root of
 * the tree. Else, <mxGraph.findTreeRoots> will be used to find a suitable
 * root node within the set of children of the given parent.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be laid out.
 * root - Optional <mxCell> that will be used as the root of the tree.
 */
mxRadialTreeLayout.prototype.execute = function(parent, root)
{
\tthis.parent = parent;
\t
\tthis.useBoundingBox = false;
\tthis.edgeRouting = false;
\t//this.horizontal = false;

\tmxCompactTreeLayout.prototype.execute.apply(this, arguments);
\t
\tvar bounds = null;
\tvar rootBounds = this.getVertexBounds(this.root);
\tthis.centerX = rootBounds.x + rootBounds.width / 2;
\tthis.centerY = rootBounds.y + rootBounds.height / 2;

\t// Calculate the bounds of the involved vertices directly from the values set in the compact tree
\tfor (var vertex in this.visited)
\t{
\t\tvar vertexBounds = this.getVertexBounds(this.visited[vertex]);
\t\tbounds = (bounds != null) ? bounds : vertexBounds.clone();
\t\tbounds.add(vertexBounds);
\t}
\t
\tthis.calcRowDims([this.node], 0);
\t
\tvar maxLeftGrad = 0;
\tvar maxRightGrad = 0;

\t// Find the steepest left and right gradients
\tfor (var i = 0; i < this.row.length; i++)
\t{
\t\tvar leftGrad = (this.centerX - this.rowMinX[i] - this.nodeDistance) / this.rowRadi[i];
\t\tvar rightGrad = (this.rowMaxX[i] - this.centerX - this.nodeDistance) / this.rowRadi[i];
\t\t
\t\tmaxLeftGrad = Math.max (maxLeftGrad, leftGrad);
\t\tmaxRightGrad = Math.max (maxRightGrad, rightGrad);
\t}
\t
\t// Extend out row so they meet the maximum gradient and convert to polar co-ords
\tfor (var i = 0; i < this.row.length; i++)
\t{
\t\tvar xLeftLimit = this.centerX - this.nodeDistance - maxLeftGrad * this.rowRadi[i];
\t\tvar xRightLimit = this.centerX + this.nodeDistance + maxRightGrad * this.rowRadi[i];
\t\tvar fullWidth = xRightLimit - xLeftLimit;
\t\t
\t\tfor (var j = 0; j < this.row[i].length; j ++)
\t\t{
\t\t\tvar row = this.row[i];
\t\t\tvar node = row[j];
\t\t\tvar vertexBounds = this.getVertexBounds(node.cell);
\t\t\tvar xProportion = (vertexBounds.x + vertexBounds.width / 2 - xLeftLimit) / (fullWidth);
\t\t\tvar theta =  2 * Math.PI * xProportion;
\t\t\tnode.theta = theta;
\t\t}
\t}

\t// Post-process from outside inwards to try to align parents with children
\tfor (var i = this.row.length - 2; i >= 0; i--)
\t{
\t\tvar row = this.row[i];
\t\t
\t\tfor (var j = 0; j < row.length; j++)
\t\t{
\t\t\tvar node = row[j];
\t\t\tvar child = node.child;
\t\t\tvar counter = 0;
\t\t\tvar totalTheta = 0;
\t\t\t
\t\t\twhile (child != null)
\t\t\t{
\t\t\t\ttotalTheta += child.theta;
\t\t\t\tcounter++;
\t\t\t\tchild = child.next;
\t\t\t}
\t\t\t
\t\t\tif (counter > 0)
\t\t\t{
\t\t\t\tvar averTheta = totalTheta / counter;
\t\t\t\t
\t\t\t\tif (averTheta > node.theta && j < row.length - 1)
\t\t\t\t{
\t\t\t\t\tvar nextTheta = row[j+1].theta;
\t\t\t\t\tnode.theta = Math.min (averTheta, nextTheta - Math.PI/10);
\t\t\t\t}
\t\t\t\telse if (averTheta < node.theta && j > 0 )
\t\t\t\t{
\t\t\t\t\tvar lastTheta = row[j-1].theta;
\t\t\t\t\tnode.theta = Math.max (averTheta, lastTheta + Math.PI/10);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\t// Set locations
\tfor (var i = 0; i < this.row.length; i++)
\t{
\t\tfor (var j = 0; j < this.row[i].length; j ++)
\t\t{
\t\t\tvar row = this.row[i];
\t\t\tvar node = row[j];
\t\t\tvar vertexBounds = this.getVertexBounds(node.cell);
\t\t\tthis.setVertexLocation(node.cell,
\t\t\t\t\t\t\t\t\tthis.centerX - vertexBounds.width / 2 + this.rowRadi[i] * Math.cos(node.theta),
\t\t\t\t\t\t\t\t\tthis.centerY - vertexBounds.height / 2 + this.rowRadi[i] * Math.sin(node.theta));
\t\t}
\t}
};

/**
 * Function: calcRowDims
 * 
 * Recursive function to calculate the dimensions of each row
 * 
 * Parameters:
 * 
 * row - Array of internal nodes, the children of which are to be processed.
 * rowNum - Integer indicating which row is being processed.
 */
mxRadialTreeLayout.prototype.calcRowDims = function(row, rowNum)
{
\tif (row == null || row.length == 0)
\t{
\t\treturn;
\t}

\t// Place root's children proportionally around the first level
\tthis.rowMinX[rowNum] = this.centerX;
\tthis.rowMaxX[rowNum] = this.centerX;
\tthis.rowMinCenX[rowNum] = this.centerX;
\tthis.rowMaxCenX[rowNum] = this.centerX;
\tthis.row[rowNum] = [];

\tvar rowHasChildren = false;

\tfor (var i = 0; i < row.length; i++)
\t{
\t\tvar child = row[i] != null ? row[i].child : null;

\t\twhile (child != null)
\t\t{
\t\t\tvar cell = child.cell;
\t\t\tvar vertexBounds = this.getVertexBounds(cell);
\t\t\t
\t\t\tthis.rowMinX[rowNum] = Math.min(vertexBounds.x, this.rowMinX[rowNum]);
\t\t\tthis.rowMaxX[rowNum] = Math.max(vertexBounds.x + vertexBounds.width, this.rowMaxX[rowNum]);
\t\t\tthis.rowMinCenX[rowNum] = Math.min(vertexBounds.x + vertexBounds.width / 2, this.rowMinCenX[rowNum]);
\t\t\tthis.rowMaxCenX[rowNum] = Math.max(vertexBounds.x + vertexBounds.width / 2, this.rowMaxCenX[rowNum]);
\t\t\tthis.rowRadi[rowNum] = vertexBounds.y - this.getVertexBounds(this.root).y;
\t
\t\t\tif (child.child != null)
\t\t\t{
\t\t\t\trowHasChildren = true;
\t\t\t}
\t\t\t
\t\t\tthis.row[rowNum].push(child);
\t\t\tchild = child.next;
\t\t}
\t}
\t
\tif (rowHasChildren)
\t{
\t\tthis.calcRowDims(this.row[rowNum], rowNum + 1);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxFastOrganicLayout
 * 
 * Extends <mxGraphLayout> to implement a fast organic layout algorithm.
 * The vertices need to be connected for this layout to work, vertices
 * with no connections are ignored.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxFastOrganicLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxCompactTreeLayout
 * 
 * Constructs a new fast organic layout for the specified graph.
 */
function mxFastOrganicLayout(graph)
{
\tmxGraphLayout.call(this, graph);
};

/**
 * Extends mxGraphLayout.
 */
mxFastOrganicLayout.prototype = new mxGraphLayout();
mxFastOrganicLayout.prototype.constructor = mxFastOrganicLayout;

/**
 * Variable: useInputOrigin
 * 
 * Specifies if the top left corner of the input cells should be the origin
 * of the layout result. Default is true.
 */
mxFastOrganicLayout.prototype.useInputOrigin = true;

/**
 * Variable: resetEdges
 * 
 * Specifies if all edge points of traversed edges should be removed.
 * Default is true.
 */
mxFastOrganicLayout.prototype.resetEdges = true;

/**
 * Variable: disableEdgeStyle
 * 
 * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are
 * modified by the result. Default is true.
 */
mxFastOrganicLayout.prototype.disableEdgeStyle = true;

/**
 * Variable: forceConstant
 * 
 * The force constant by which the attractive forces are divided and the
 * replusive forces are multiple by the square of. The value equates to the
 * average radius there is of free space around each node. Default is 50.
 */
mxFastOrganicLayout.prototype.forceConstant = 50;

/**
 * Variable: forceConstantSquared
 * 
 * Cache of <forceConstant>^2 for performance.
 */
mxFastOrganicLayout.prototype.forceConstantSquared = 0;

/**
 * Variable: minDistanceLimit
 * 
 * Minimal distance limit. Default is 2. Prevents of
 * dividing by zero.
 */
mxFastOrganicLayout.prototype.minDistanceLimit = 2;

/**
 * Variable: maxDistanceLimit
 * 
 * Maximal distance limit. Default is 500. Prevents of
 * dividing by zero.
 */
mxFastOrganicLayout.prototype.maxDistanceLimit = 500;

/**
 * Variable: minDistanceLimitSquared
 * 
 * Cached version of <minDistanceLimit> squared.
 */
mxFastOrganicLayout.prototype.minDistanceLimitSquared = 4;

/**
 * Variable: initialTemp
 * 
 * Start value of temperature. Default is 200.
 */
mxFastOrganicLayout.prototype.initialTemp = 200;

/**
 * Variable: temperature
 * 
 * Temperature to limit displacement at later stages of layout.
 */
mxFastOrganicLayout.prototype.temperature = 0;

/**
 * Variable: maxIterations
 * 
 * Total number of iterations to run the layout though.
 */
mxFastOrganicLayout.prototype.maxIterations = 0;

/**
 * Variable: iteration
 * 
 * Current iteration count.
 */
mxFastOrganicLayout.prototype.iteration = 0;

/**
 * Variable: vertexArray
 * 
 * An array of all vertices to be laid out.
 */
mxFastOrganicLayout.prototype.vertexArray;

/**
 * Variable: dispX
 * 
 * An array of locally stored X co-ordinate displacements for the vertices.
 */
mxFastOrganicLayout.prototype.dispX;

/**
 * Variable: dispY
 * 
 * An array of locally stored Y co-ordinate displacements for the vertices.
 */
mxFastOrganicLayout.prototype.dispY;

/**
 * Variable: cellLocation
 * 
 * An array of locally stored co-ordinate positions for the vertices.
 */
mxFastOrganicLayout.prototype.cellLocation;

/**
 * Variable: radius
 * 
 * The approximate radius of each cell, nodes only.
 */
mxFastOrganicLayout.prototype.radius;

/**
 * Variable: radiusSquared
 * 
 * The approximate radius squared of each cell, nodes only.
 */
mxFastOrganicLayout.prototype.radiusSquared;

/**
 * Variable: isMoveable
 * 
 * Array of booleans representing the movable states of the vertices.
 */
mxFastOrganicLayout.prototype.isMoveable;

/**
 * Variable: neighbours
 * 
 * Local copy of cell neighbours.
 */
mxFastOrganicLayout.prototype.neighbours;

/**
 * Variable: indices
 * 
 * Hashtable from cells to local indices.
 */
mxFastOrganicLayout.prototype.indices;

/**
 * Variable: allowedToRun
 * 
 * Boolean flag that specifies if the layout is allowed to run. If this is
 * set to false, then the layout exits in the following iteration.
 */
mxFastOrganicLayout.prototype.allowedToRun = true;

/**
 * Function: isVertexIgnored
 * 
 * Returns a boolean indicating if the given <mxCell> should be ignored as a
 * vertex. This returns true if the cell has no connections.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> whose ignored state should be returned.
 */
mxFastOrganicLayout.prototype.isVertexIgnored = function(vertex)
{
\treturn mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
\t\tthis.graph.getConnections(vertex).length == 0;
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>. This operates on all children of the
 * given parent where <isVertexIgnored> returns false.
 */
mxFastOrganicLayout.prototype.execute = function(parent)
{
\tvar model = this.graph.getModel();
\tthis.vertexArray = [];
\tvar cells = this.graph.getChildVertices(parent);
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tif (!this.isVertexIgnored(cells[i]))
\t\t{
\t\t\tthis.vertexArray.push(cells[i]);
\t\t}
\t}
\t
\tvar initialBounds = (this.useInputOrigin) ?
\t\t\tthis.graph.getBoundingBoxFromGeometry(this.vertexArray) :
\t\t\t\tnull;
\tvar n = this.vertexArray.length;

\tthis.indices = [];
\tthis.dispX = [];
\tthis.dispY = [];
\tthis.cellLocation = [];
\tthis.isMoveable = [];
\tthis.neighbours = [];
\tthis.radius = [];
\tthis.radiusSquared = [];

\tif (this.forceConstant < 0.001)
\t{
\t\tthis.forceConstant = 0.001;
\t}

\tthis.forceConstantSquared = this.forceConstant * this.forceConstant;

\t// Create a map of vertices first. This is required for the array of
\t// arrays called neighbours which holds, for each vertex, a list of
\t// ints which represents the neighbours cells to that vertex as
\t// the indices into vertexArray
\tfor (var i = 0; i < this.vertexArray.length; i++)
\t{
\t\tvar vertex = this.vertexArray[i];
\t\tthis.cellLocation[i] = [];
\t\t
\t\t// Set up the mapping from array indices to cells
\t\tvar id = mxObjectIdentity.get(vertex);
\t\tthis.indices[id] = i;
\t\tvar bounds = this.getVertexBounds(vertex);

\t\t// Set the X,Y value of the internal version of the cell to
\t\t// the center point of the vertex for better positioning
\t\tvar width = bounds.width;
\t\tvar height = bounds.height;
\t\t
\t\t// Randomize (0, 0) locations
\t\tvar x = bounds.x;
\t\tvar y = bounds.y;
\t\t
\t\tthis.cellLocation[i][0] = x + width / 2.0;
\t\tthis.cellLocation[i][1] = y + height / 2.0;
\t\tthis.radius[i] = Math.min(width, height);
\t\tthis.radiusSquared[i] = this.radius[i] * this.radius[i];
\t}

\t// Moves cell location back to top-left from center locations used in
\t// algorithm, resetting the edge points is part of the transaction
\tmodel.beginUpdate();
\ttry
\t{
\t\tfor (var i = 0; i < n; i++)
\t\t{
\t\t\tthis.dispX[i] = 0;
\t\t\tthis.dispY[i] = 0;
\t\t\tthis.isMoveable[i] = this.isVertexMovable(this.vertexArray[i]);

\t\t\t// Get lists of neighbours to all vertices, translate the cells
\t\t\t// obtained in indices into vertexArray and store as an array
\t\t\t// against the orginial cell index
\t\t\tvar edges = this.graph.getConnections(this.vertexArray[i], parent);
\t\t\tvar cells = this.graph.getOpposites(edges, this.vertexArray[i]);
\t\t\tthis.neighbours[i] = [];

\t\t\tfor (var j = 0; j < cells.length; j++)
\t\t\t{
\t\t\t\t// Resets the points on the traversed edge
\t\t\t\tif (this.resetEdges)
\t\t\t\t{
\t\t\t\t\tthis.graph.resetEdge(edges[j]);
\t\t\t\t}

\t\t\t    if (this.disableEdgeStyle)
\t\t\t    {
\t\t\t    \tthis.setEdgeStyleEnabled(edges[j], false);
\t\t\t    }

\t\t\t\t// Looks the cell up in the indices dictionary
\t\t\t\tvar id = mxObjectIdentity.get(cells[j]);
\t\t\t\tvar index = this.indices[id];

\t\t\t\t// Check the connected cell in part of the vertex list to be
\t\t\t\t// acted on by this layout
\t\t\t\tif (index != null)
\t\t\t\t{
\t\t\t\t\tthis.neighbours[i][j] = index;
\t\t\t\t}

\t\t\t\t// Else if index of the other cell doesn't correspond to
\t\t\t\t// any cell listed to be acted upon in this layout. Set
\t\t\t\t// the index to the value of this vertex (a dummy self-loop)
\t\t\t\t// so the attraction force of the edge is not calculated
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.neighbours[i][j] = i;
\t\t\t\t}
\t\t\t}
\t\t}
\t\tthis.temperature = this.initialTemp;

\t\t// If max number of iterations has not been set, guess it
\t\tif (this.maxIterations == 0)
\t\t{
\t\t\tthis.maxIterations = 20 * Math.sqrt(n);
\t\t}
\t\t
\t\t// Main iteration loop
\t\tfor (this.iteration = 0; this.iteration < this.maxIterations; this.iteration++)
\t\t{
\t\t\tif (!this.allowedToRun)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\t// Calculate repulsive forces on all vertices
\t\t\tthis.calcRepulsion();

\t\t\t// Calculate attractive forces through edges
\t\t\tthis.calcAttraction();

\t\t\tthis.calcPositions();
\t\t\tthis.reduceTemperature();
\t\t}

\t\tvar minx = null;
\t\tvar miny = null;
\t\t
\t\tfor (var i = 0; i < this.vertexArray.length; i++)
\t\t{
\t\t\tvar vertex = this.vertexArray[i];
\t\t\t
\t\t\tif (this.isVertexMovable(vertex))
\t\t\t{
\t\t\t\tvar bounds = this.getVertexBounds(vertex);
\t\t\t\t
\t\t\t\tif (bounds != null)
\t\t\t\t{
\t\t\t\t\tthis.cellLocation[i][0] -= bounds.width / 2.0;
\t\t\t\t\tthis.cellLocation[i][1] -= bounds.height / 2.0;
\t\t\t\t\t
\t\t\t\t\tvar x = this.graph.snap(Math.round(this.cellLocation[i][0]));
\t\t\t\t\tvar y = this.graph.snap(Math.round(this.cellLocation[i][1]));
\t\t\t\t\t
\t\t\t\t\tthis.setVertexLocation(vertex, x, y);
\t\t\t\t\t
\t\t\t\t\tif (minx == null)
\t\t\t\t\t{
\t\t\t\t\t\tminx = x;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tminx = Math.min(minx, x);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (miny == null)
\t\t\t\t\t{
\t\t\t\t\t\tminy = y;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tminy = Math.min(miny, y);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\t// Modifies the cloned geometries in-place. Not needed
\t\t// to clone the geometries again as we're in the same
\t\t// undoable change.
\t\tvar dx = -(minx || 0) + 1;
\t\tvar dy = -(miny || 0) + 1;
\t\t
\t\tif (initialBounds != null)
\t\t{
\t\t\tdx += initialBounds.x;
\t\t\tdy += initialBounds.y;
\t\t}
\t\t
\t\tthis.graph.moveCells(this.vertexArray, dx, dy);
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: calcPositions
 * 
 * Takes the displacements calculated for each cell and applies them to the
 * local cache of cell positions. Limits the displacement to the current
 * temperature.
 */
mxFastOrganicLayout.prototype.calcPositions = function()
{
\tfor (var index = 0; index < this.vertexArray.length; index++)
\t{
\t\tif (this.isMoveable[index])
\t\t{
\t\t\t// Get the distance of displacement for this node for this
\t\t\t// iteration
\t\t\tvar deltaLength = Math.sqrt(this.dispX[index] * this.dispX[index] +
\t\t\t\tthis.dispY[index] * this.dispY[index]);

\t\t\tif (deltaLength < 0.001)
\t\t\t{
\t\t\t\tdeltaLength = 0.001;
\t\t\t}

\t\t\t// Scale down by the current temperature if less than the
\t\t\t// displacement distance
\t\t\tvar newXDisp = this.dispX[index] / deltaLength
\t\t\t\t* Math.min(deltaLength, this.temperature);

\t\t\tvar newYDisp = this.dispY[index] / deltaLength
\t\t\t\t* Math.min(deltaLength, this.temperature);

\t\t\t// reset displacements
\t\t\tthis.dispX[index] = 0;
\t\t\tthis.dispY[index] = 0;

\t\t\t// Update the cached cell locations
\t\t\tthis.cellLocation[index][0] += newXDisp;
\t\t\tthis.cellLocation[index][1] += newYDisp;
\t\t}
\t}
};

/**
 * Function: calcAttraction
 * 
 * Calculates the attractive forces between all laid out nodes linked by
 * edges
 */
mxFastOrganicLayout.prototype.calcAttraction = function()
{
\t// Check the neighbours of each vertex and calculate the attractive
\t// force of the edge connecting them
\tfor (var i = 0; i < this.vertexArray.length; i++)
\t{
\t\tfor (var k = 0; k < this.neighbours[i].length; k++)
\t\t{
\t\t\t// Get the index of the othe cell in the vertex array
\t\t\tvar j = this.neighbours[i][k];
\t\t\t
\t\t\t// Do not proceed self-loops
\t\t\tif (i != j &&
\t\t\t\tthis.isMoveable[i] &&
\t\t\t\tthis.isMoveable[j])
\t\t\t{
\t\t\t\tvar xDelta = this.cellLocation[i][0] - this.cellLocation[j][0];
\t\t\t\tvar yDelta = this.cellLocation[i][1] - this.cellLocation[j][1];

\t\t\t\t// The distance between the nodes
\t\t\t\tvar deltaLengthSquared = xDelta * xDelta + yDelta
\t\t\t\t\t\t* yDelta - this.radiusSquared[i] - this.radiusSquared[j];

\t\t\t\tif (deltaLengthSquared < this.minDistanceLimitSquared)
\t\t\t\t{
\t\t\t\t\tdeltaLengthSquared = this.minDistanceLimitSquared;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar deltaLength = Math.sqrt(deltaLengthSquared);
\t\t\t\tvar force = (deltaLengthSquared) / this.forceConstant;

\t\t\t\tvar displacementX = (xDelta / deltaLength) * force;
\t\t\t\tvar displacementY = (yDelta / deltaLength) * force;
\t\t\t\t
\t\t\t\tthis.dispX[i] -= displacementX;
\t\t\t\tthis.dispY[i] -= displacementY;
\t\t\t\t
\t\t\t\tthis.dispX[j] += displacementX;
\t\t\t\tthis.dispY[j] += displacementY;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: calcRepulsion
 * 
 * Calculates the repulsive forces between all laid out nodes
 */
mxFastOrganicLayout.prototype.calcRepulsion = function()
{
\tvar vertexCount = this.vertexArray.length;

\tfor (var i = 0; i < vertexCount; i++)
\t{
\t\tfor (var j = i; j < vertexCount; j++)
\t\t{
\t\t\t// Exits if the layout is no longer allowed to run
\t\t\tif (!this.allowedToRun)
\t\t\t{
\t\t\t\treturn;
\t\t\t}

\t\t\tif (j != i &&
\t\t\t\tthis.isMoveable[i] &&
\t\t\t\tthis.isMoveable[j])
\t\t\t{
\t\t\t\tvar xDelta = this.cellLocation[i][0] - this.cellLocation[j][0];
\t\t\t\tvar yDelta = this.cellLocation[i][1] - this.cellLocation[j][1];

\t\t\t\tif (xDelta == 0)
\t\t\t\t{
\t\t\t\t\txDelta = 0.01 + Math.random();
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (yDelta == 0)
\t\t\t\t{
\t\t\t\t\tyDelta = 0.01 + Math.random();
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Distance between nodes
\t\t\t\tvar deltaLength = Math.sqrt((xDelta * xDelta)
\t\t\t\t\t\t+ (yDelta * yDelta));
\t\t\t\tvar deltaLengthWithRadius = deltaLength - this.radius[i]
\t\t\t\t\t\t- this.radius[j];

\t\t\t\tif (deltaLengthWithRadius > this.maxDistanceLimit)
\t\t\t\t{
\t\t\t\t\t// Ignore vertices too far apart
\t\t\t\t\tcontinue;
\t\t\t\t}

\t\t\t\tif (deltaLengthWithRadius < this.minDistanceLimit)
\t\t\t\t{
\t\t\t\t\tdeltaLengthWithRadius = this.minDistanceLimit;
\t\t\t\t}

\t\t\t\tvar force = this.forceConstantSquared / deltaLengthWithRadius;

\t\t\t\tvar displacementX = (xDelta / deltaLength) * force;
\t\t\t\tvar displacementY = (yDelta / deltaLength) * force;
\t\t\t\t
\t\t\t\tthis.dispX[i] += displacementX;
\t\t\t\tthis.dispY[i] += displacementY;

\t\t\t\tthis.dispX[j] -= displacementX;
\t\t\t\tthis.dispY[j] -= displacementY;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: reduceTemperature
 * 
 * Reduces the temperature of the layout from an initial setting in a linear
 * fashion to zero.
 */
mxFastOrganicLayout.prototype.reduceTemperature = function()
{
\tthis.temperature = this.initialTemp * (1.0 - this.iteration / this.maxIterations);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCircleLayout
 * 
 * Extends <mxGraphLayout> to implement a circluar layout for a given radius.
 * The vertices do not need to be connected for this layout to work and all
 * connections between vertices are not taken into account.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxCircleLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxCircleLayout
 *
 * Constructs a new circular layout for the specified radius.
 *
 * Arguments:
 * 
 * graph - <mxGraph> that contains the cells.
 * radius - Optional radius as an int. Default is 100.
 */
function mxCircleLayout(graph, radius)
{
\tmxGraphLayout.call(this, graph);
\tthis.radius = (radius != null) ? radius : 100;
};

/**
 * Extends mxGraphLayout.
 */
mxCircleLayout.prototype = new mxGraphLayout();
mxCircleLayout.prototype.constructor = mxCircleLayout;

/**
 * Variable: radius
 * 
 * Integer specifying the size of the radius. Default is 100.
 */
mxCircleLayout.prototype.radius = null;

/**
 * Variable: moveCircle
 * 
 * Boolean specifying if the circle should be moved to the top,
 * left corner specified by <x0> and <y0>. Default is false.
 */
mxCircleLayout.prototype.moveCircle = false;

/**
 * Variable: x0
 * 
 * Integer specifying the left coordinate of the circle.
 * Default is 0.
 */
mxCircleLayout.prototype.x0 = 0;

/**
 * Variable: y0
 * 
 * Integer specifying the top coordinate of the circle.
 * Default is 0.
 */
mxCircleLayout.prototype.y0 = 0;

/**
 * Variable: resetEdges
 * 
 * Specifies if all edge points of traversed edges should be removed.
 * Default is true.
 */
mxCircleLayout.prototype.resetEdges = true;

/**
 * Variable: disableEdgeStyle
 * 
 * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are
 * modified by the result. Default is true.
 */
mxCircleLayout.prototype.disableEdgeStyle = true;

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 */
mxCircleLayout.prototype.execute = function(parent)
{
\tvar model = this.graph.getModel();

\t// Moves the vertices to build a circle. Makes sure the
\t// radius is large enough for the vertices to not
\t// overlap
\tmodel.beginUpdate();
\ttry
\t{
\t\t// Gets all vertices inside the parent and finds
\t\t// the maximum dimension of the largest vertex
\t\tvar max = 0;
\t\tvar top = null;
\t\tvar left = null;
\t\tvar vertices = [];
\t\tvar childCount = model.getChildCount(parent);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar cell = model.getChildAt(parent, i);
\t\t\t
\t\t\tif (!this.isVertexIgnored(cell))
\t\t\t{
\t\t\t\tvertices.push(cell);
\t\t\t\tvar bounds = this.getVertexBounds(cell);
\t\t\t\t
\t\t\t\tif (top == null)
\t\t\t\t{
\t\t\t\t\ttop = bounds.y;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttop = Math.min(top, bounds.y);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (left == null)
\t\t\t\t{
\t\t\t\t\tleft = bounds.x;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tleft = Math.min(left, bounds.x);
\t\t\t\t}
\t\t\t\t
\t\t\t\tmax = Math.max(max, Math.max(bounds.width, bounds.height));
\t\t\t}
\t\t\telse if (!this.isEdgeIgnored(cell))
\t\t\t{
\t\t\t\t// Resets the points on the traversed edge
\t\t\t\tif (this.resetEdges)
\t\t\t\t{
\t\t\t\t\tthis.graph.resetEdge(cell);
\t\t\t\t}

\t\t\t    if (this.disableEdgeStyle)
\t\t\t    {
\t\t\t    \t\tthis.setEdgeStyleEnabled(cell, false);
\t\t\t    }
\t\t\t}
\t\t}
\t\t
\t\tvar r = this.getRadius(vertices.length, max);

\t\t// Moves the circle to the specified origin
\t\tif (this.moveCircle)
\t\t{
\t\t\tleft = this.x0;
\t\t\ttop = this.y0;
\t\t}
\t\t
\t\tthis.circle(vertices, r, left, top);
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: getRadius
 * 
 * Returns the radius to be used for the given vertex count. Max is the maximum
 * width or height of all vertices in the layout.
 */
mxCircleLayout.prototype.getRadius = function(count, max)
{
\treturn Math.max(count * max / Math.PI, this.radius);
};

/**
 * Function: circle
 * 
 * Executes the circular layout for the specified array
 * of vertices and the given radius. This is called from
 * <execute>.
 */
mxCircleLayout.prototype.circle = function(vertices, r, left, top)
{
\tvar vertexCount = vertices.length;
\tvar phi = 2 * Math.PI / vertexCount;
\t
\tfor (var i = 0; i < vertexCount; i++)
\t{
\t\tif (this.isVertexMovable(vertices[i]))
\t\t{
\t\t\tthis.setVertexLocation(vertices[i],
\t\t\t\tMath.round(left + r + r * Math.sin(i * phi)),
\t\t\t\tMath.round(top + r + r * Math.cos(i * phi)));
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxParallelEdgeLayout
 * 
 * Extends <mxGraphLayout> for arranging parallel edges. This layout works
 * on edges for all pairs of vertices where there is more than one edge
 * connecting the latter.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxParallelEdgeLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * To run the layout for the parallel edges of a changed edge only, the
 * following code can be used.
 * 
 * (code)
 * var layout = new mxParallelEdgeLayout(graph);
 * 
 * graph.addListener(mxEvent.CELL_CONNECTED, function(sender, evt)
 * {
 *   var model = graph.getModel();
 *   var edge = evt.getProperty('edge');
 *   var src = model.getTerminal(edge, true);
 *   var trg = model.getTerminal(edge, false);
 *   
 *   layout.isEdgeIgnored = function(edge2)
 *   {
 *     var src2 = model.getTerminal(edge2, true);
 *     var trg2 = model.getTerminal(edge2, false);
 *     
 *     return !(model.isEdge(edge2) && ((src == src2 && trg == trg2) || (src == trg2 && trg == src2)));
 *   };
 *   
 *   layout.execute(graph.getDefaultParent());
 * });
 * (end)
 * 
 * Constructor: mxParallelEdgeLayout
 * 
 * Constructs a new parallel edge layout for the specified graph.
 */
function mxParallelEdgeLayout(graph)
{
\tmxGraphLayout.call(this, graph);
};

/**
 * Extends mxGraphLayout.
 */
mxParallelEdgeLayout.prototype = new mxGraphLayout();
mxParallelEdgeLayout.prototype.constructor = mxParallelEdgeLayout;

/**
 * Variable: spacing
 * 
 * Defines the spacing between the parallels. Default is 20.
 */
mxParallelEdgeLayout.prototype.spacing = 20;

/**
 * Variable: checkOverlap
 * 
 * Specifies if only overlapping edges should be considered
 * parallel. Default is false.
 */
mxParallelEdgeLayout.prototype.checkOverlap = false;

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 */
mxParallelEdgeLayout.prototype.execute = function(parent, cells)
{
\tvar lookup = this.findParallels(parent, cells);
\t
\tthis.graph.model.beginUpdate();\t
\ttry
\t{
\t\tfor (var i in lookup)
\t\t{
\t\t\tvar parallels = lookup[i];

\t\t\tif (parallels.length > 1)
\t\t\t{
\t\t\t\tthis.layout(parallels);
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tthis.graph.model.endUpdate();
\t}
};

/**
 * Function: findParallels
 * 
 * Finds the parallel edges in the given parent.
 */
mxParallelEdgeLayout.prototype.findParallels = function(parent, cells)
{
\tvar lookup = [];
\t
\tvar addCell = mxUtils.bind(this, function(cell)
\t{
\t\tif (!this.isEdgeIgnored(cell))
\t\t{
\t\t\tvar id = this.getEdgeId(cell);
\t\t\t
\t\t\tif (id != null)
\t\t\t{
\t\t\t\tif (lookup[id] == null)
\t\t\t\t{
\t\t\t\t\tlookup[id] = [];
\t\t\t\t}
\t\t\t\t
\t\t\t\tlookup[id].push(cell);
\t\t\t}
\t\t}
\t});
\t
\tif (cells != null)
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\taddCell(cells[i]);
\t\t}
\t}
\telse
\t{
\t\tvar model = this.graph.getModel();
\t\tvar childCount = model.getChildCount(parent);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\taddCell(model.getChildAt(parent, i));
\t\t}
\t}
\t
\treturn lookup;
};

/**
 * Function: getEdgeId
 * 
 * Returns a unique ID for the given edge. The id is independent of the
 * edge direction and is built using the visible terminal of the given
 * edge.
 */
mxParallelEdgeLayout.prototype.getEdgeId = function(edge)
{
\tvar view = this.graph.getView();
\t
\t// Cannot used cached visible terminal because this could be triggered in BEFORE_UNDO
\tvar src = view.getVisibleTerminal(edge, true);
\tvar trg = view.getVisibleTerminal(edge, false);
\tvar pts = '';

\tif (src != null && trg != null)
\t{
\t\tsrc = mxObjectIdentity.get(src);
\t\ttrg = mxObjectIdentity.get(trg);
\t\t
\t\tif (this.checkOverlap)
\t\t{
\t\t\tvar state = this.graph.view.getState(edge);
\t\t\t
\t\t\tif (state != null && state.absolutePoints != null)
\t\t\t{
\t\t\t\tvar tmp = [];
\t\t\t\t
\t\t\t\tfor (var i = 0; i < state.absolutePoints.length; i++)
\t\t\t\t{
\t\t\t\t\tvar pt = state.absolutePoints[i];
\t\t\t\t\t
\t\t\t\t\tif (pt != null)
\t\t\t\t\t{
\t\t\t\t\t\ttmp.push(pt.x, pt.y);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tpts = tmp.join(',');
\t\t\t}
\t\t};
\t\t
\t\treturn ((src > trg) ? trg + '-' + src : src + '-' + trg) + pts;
\t}
\t
\treturn null;
};

/**
 * Function: layout
 * 
 * Lays out the parallel edges in the given array.
 */
mxParallelEdgeLayout.prototype.layout = function(parallels)
{
\tvar edge = parallels[0];
\tvar view = this.graph.getView();
\tvar model = this.graph.getModel();
\tvar src = model.getGeometry(view.getVisibleTerminal(edge, true));
\tvar trg = model.getGeometry(view.getVisibleTerminal(edge, false));
\t
\t// Routes multiple loops
\tif (src == trg)
\t{
\t\tvar x0 = src.x + src.width + this.spacing;
\t\tvar y0 = src.y + src.height / 2;

\t\tfor (var i = 0; i < parallels.length; i++)
\t\t{
\t\t\tthis.route(parallels[i], x0, y0);
\t\t\tx0 += this.spacing;
\t\t}
\t}
\telse if (src != null && trg != null)
\t{
\t\t// Routes parallel edges
\t\tvar scx = src.x + src.width / 2;
\t\tvar scy = src.y + src.height / 2;
\t\t
\t\tvar tcx = trg.x + trg.width / 2;
\t\tvar tcy = trg.y + trg.height / 2;
\t\t
\t\tvar dx = tcx - scx;
\t\tvar dy = tcy - scy;

\t\tvar len = Math.sqrt(dx * dx + dy * dy);
\t\t
\t\tif (len > 0)
\t\t{
\t\t\tvar x0 = scx + dx / 2;
\t\t\tvar y0 = scy + dy / 2;
\t\t\t
\t\t\tvar nx = dy * this.spacing / len;
\t\t\tvar ny = dx * this.spacing / len;
\t\t\t
\t\t\tx0 += nx * (parallels.length - 1) / 2;
\t\t\ty0 -= ny * (parallels.length - 1) / 2;
\t
\t\t\tfor (var i = 0; i < parallels.length; i++)
\t\t\t{
\t\t\t\tthis.route(parallels[i], x0, y0);
\t\t\t\tx0 -= nx;
\t\t\t\ty0 += ny;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: route
 * 
 * Routes the given edge via the given point.
 */
mxParallelEdgeLayout.prototype.route = function(edge, x, y)
{
\tif (this.graph.isCellMovable(edge))
\t{
\t\tthis.setEdgePoints(edge, [new mxPoint(x, y)]);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCompositeLayout
 * 
 * Allows to compose multiple layouts into a single layout. The master layout
 * is the layout that handles move operations if another layout than the first
 * element in <layouts> should be used. The <master> layout is not executed as
 * the code assumes that it is part of <layouts>.
 * 
 * Example:
 * (code)
 * var first = new mxFastOrganicLayout(graph);
 * var second = new mxParallelEdgeLayout(graph);
 * var layout = new mxCompositeLayout(graph, [first, second], first);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxCompositeLayout
 *
 * Constructs a new layout using the given layouts. The graph instance is
 * required for creating the transaction that contains all layouts.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * layouts - Array of <mxGraphLayouts>.
 * master - Optional layout that handles moves. If no layout is given then
 * the first layout of the above array is used to handle moves.
 */
function mxCompositeLayout(graph, layouts, master)
{
\tmxGraphLayout.call(this, graph);
\tthis.layouts = layouts;
\tthis.master = master;
};

/**
 * Extends mxGraphLayout.
 */
mxCompositeLayout.prototype = new mxGraphLayout();
mxCompositeLayout.prototype.constructor = mxCompositeLayout;
\t
/**
 * Variable: layouts
 * 
 * Holds the array of <mxGraphLayouts> that this layout contains.
 */
mxCompositeLayout.prototype.layouts = null;

/**
 * Variable: master
 * 
 * Reference to the <mxGraphLayouts> that handles moves. If this is null
 * then the first layout in <layouts> is used.
 */
mxCompositeLayout.prototype.master = null;

/**
 * Function: moveCell
 * 
 * Implements <mxGraphLayout.moveCell> by calling move on <master> or the first
 * layout in <layouts>.
 */
mxCompositeLayout.prototype.moveCell = function(cell, x, y)
{
\tif (this.master != null)
\t{
\t\tthis.master.moveCell.apply(this.master, arguments);
\t}
\telse
\t{
\t\tthis.layouts[0].moveCell.apply(this.layouts[0], arguments);
\t}
};

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute> by executing all <layouts> in a
 * single transaction.
 */
mxCompositeLayout.prototype.execute = function(parent)
{
\tvar model = this.graph.getModel();
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tfor (var i = 0; i < this.layouts.length; i++)
\t\t{
\t\t\tthis.layouts[i].execute.apply(this.layouts[i], arguments);
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxEdgeLabelLayout
 * 
 * Extends <mxGraphLayout> to implement an edge label layout. This layout
 * makes use of cell states, which means the graph must be validated in
 * a graph view (so that the label bounds are available) before this layout
 * can be executed.
 * 
 * Example:
 * 
 * (code)
 * var layout = new mxEdgeLabelLayout(graph);
 * layout.execute(graph.getDefaultParent());
 * (end)
 * 
 * Constructor: mxEdgeLabelLayout
 *
 * Constructs a new edge label layout.
 *
 * Arguments:
 * 
 * graph - <mxGraph> that contains the cells.
 */
function mxEdgeLabelLayout(graph, radius)
{
\tmxGraphLayout.call(this, graph);
};

/**
 * Extends mxGraphLayout.
 */
mxEdgeLabelLayout.prototype = new mxGraphLayout();
mxEdgeLabelLayout.prototype.constructor = mxEdgeLabelLayout;

/**
 * Function: execute
 * 
 * Implements <mxGraphLayout.execute>.
 */
mxEdgeLabelLayout.prototype.execute = function(parent)
{
\tvar view = this.graph.view;
\tvar model = this.graph.getModel();
\t
\t// Gets all vertices and edges inside the parent
\tvar edges = [];
\tvar vertices = [];
\tvar childCount = model.getChildCount(parent);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar cell = model.getChildAt(parent, i);
\t\tvar state = view.getState(cell);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tif (!this.isVertexIgnored(cell))
\t\t\t{
\t\t\t\tvertices.push(state);
\t\t\t}
\t\t\telse if (!this.isEdgeIgnored(cell))
\t\t\t{
\t\t\t\tedges.push(state);
\t\t\t}
\t\t}
\t}
\t
\tthis.placeLabels(vertices, edges);
};

/**
 * Function: placeLabels
 * 
 * Places the labels of the given edges.
 */
mxEdgeLabelLayout.prototype.placeLabels = function(v, e)
{
\tvar model = this.graph.getModel();
\t
\t// Moves the vertices to build a circle. Makes sure the
\t// radius is large enough for the vertices to not
\t// overlap
\tmodel.beginUpdate();
\ttry
\t{
\t\tfor (var i = 0; i < e.length; i++)
\t\t{
\t\t\tvar edge = e[i];
\t\t\t
\t\t\tif (edge != null && edge.text != null &&
\t\t\t\tedge.text.boundingBox != null)
\t\t\t{
\t\t\t\tfor (var j = 0; j < v.length; j++)
\t\t\t\t{
\t\t\t\t\tvar vertex = v[j];
\t\t\t\t\t
\t\t\t\t\tif (vertex != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.avoid(edge, vertex);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: avoid
 * 
 * Places the labels of the given edges.
 */
mxEdgeLabelLayout.prototype.avoid = function(edge, vertex)
{
\tvar model = this.graph.getModel();
\tvar labRect = edge.text.boundingBox;
\t
\tif (mxUtils.intersects(labRect, vertex))
\t{
\t\tvar dy1 = -labRect.y - labRect.height + vertex.y;
\t\tvar dy2 = -labRect.y + vertex.y + vertex.height;
\t\t
\t\tvar dy = (Math.abs(dy1) < Math.abs(dy2)) ? dy1 : dy2;
\t\t
\t\tvar dx1 = -labRect.x - labRect.width + vertex.x;
\t\tvar dx2 = -labRect.x + vertex.x + vertex.width;
\t
\t\tvar dx = (Math.abs(dx1) < Math.abs(dx2)) ? dx1 : dx2;
\t\t
\t\tif (Math.abs(dx) < Math.abs(dy))
\t\t{
\t\t\tdy = 0;
\t\t}
\t\telse
\t\t{
\t\t\tdx = 0;
\t\t}
\t
\t\tvar g = model.getGeometry(edge.cell);
\t\t
\t\tif (g != null)
\t\t{
\t\t\tg = g.clone();
\t\t\t
\t\t\tif (g.offset != null)
\t\t\t{
\t\t\t\tg.offset.x += dx;
\t\t\t\tg.offset.y += dy;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tg.offset = new mxPoint(dx, dy);
\t\t\t}
\t\t\t
\t\t\tmodel.setGeometry(edge.cell, g);
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphAbstractHierarchyCell
 * 
 * An abstraction of an internal hierarchy node or edge
 * 
 * Constructor: mxGraphAbstractHierarchyCell
 *
 * Constructs a new hierarchical layout algorithm.
 */
function mxGraphAbstractHierarchyCell()
{
\tthis.x = [];
\tthis.y = [];
\tthis.temp = [];
};

/**
 * Variable: maxRank
 * 
 * The maximum rank this cell occupies. Default is -1.
 */
mxGraphAbstractHierarchyCell.prototype.maxRank = -1;

/**
 * Variable: minRank
 * 
 * The minimum rank this cell occupies. Default is -1.
 */
mxGraphAbstractHierarchyCell.prototype.minRank = -1;

/**
 * Variable: x
 * 
 * The x position of this cell for each layer it occupies
 */
mxGraphAbstractHierarchyCell.prototype.x = null;

/**
 * Variable: y
 * 
 * The y position of this cell for each layer it occupies
 */
mxGraphAbstractHierarchyCell.prototype.y = null;

/**
 * Variable: width
 * 
 * The width of this cell. Default is 0.
 */
mxGraphAbstractHierarchyCell.prototype.width = 0;

/**
 * Variable: height
 * 
 * The height of this cell. Default is 0.
 */
mxGraphAbstractHierarchyCell.prototype.height = 0;

/**
 * Variable: nextLayerConnectedCells
 * 
 * A cached version of the cells this cell connects to on the next layer up
 */
mxGraphAbstractHierarchyCell.prototype.nextLayerConnectedCells = null;

/**
 * Variable: previousLayerConnectedCells
 * 
 * A cached version of the cells this cell connects to on the next layer down
 */
mxGraphAbstractHierarchyCell.prototype.previousLayerConnectedCells = null;

/**
 * Variable: temp
 * 
 * Temporary variable for general use. Generally, try to avoid
 * carrying information between stages. Currently, the longest
 * path layering sets temp to the rank position in fixRanks()
 * and the crossing reduction uses this. This meant temp couldn't
 * be used for hashing the nodes in the model dfs and so hashCode
 * was created
 */
mxGraphAbstractHierarchyCell.prototype.temp = null;

/**
 * Function: getNextLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer up
 */
mxGraphAbstractHierarchyCell.prototype.getNextLayerConnectedCells = function(layer)
{
\treturn null;
};

/**
 * Function: getPreviousLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer down
 */
mxGraphAbstractHierarchyCell.prototype.getPreviousLayerConnectedCells = function(layer)
{
\treturn null;
};

/**
 * Function: isEdge
 * 
 * Returns whether or not this cell is an edge
 */
mxGraphAbstractHierarchyCell.prototype.isEdge = function()
{
\treturn false;
};

/**
 * Function: isVertex
 * 
 * Returns whether or not this cell is a node
 */
mxGraphAbstractHierarchyCell.prototype.isVertex = function()
{
\treturn false;
};

/**
 * Function: getGeneralPurposeVariable
 * 
 * Gets the value of temp for the specified layer
 */
mxGraphAbstractHierarchyCell.prototype.getGeneralPurposeVariable = function(layer)
{
\treturn null;
};

/**
 * Function: setGeneralPurposeVariable
 * 
 * Set the value of temp for the specified layer
 */
mxGraphAbstractHierarchyCell.prototype.setGeneralPurposeVariable = function(layer, value)
{
\treturn null;
};

/**
 * Function: setX
 * 
 * Set the value of x for the specified layer
 */
mxGraphAbstractHierarchyCell.prototype.setX = function(layer, value)
{
\tif (this.isVertex())
\t{
\t\tthis.x[0] = value;
\t}
\telse if (this.isEdge())
\t{
\t\tthis.x[layer - this.minRank - 1] = value;
\t}
};

/**
 * Function: getX
 * 
 * Gets the value of x on the specified layer
 */
mxGraphAbstractHierarchyCell.prototype.getX = function(layer)
{
\tif (this.isVertex())
\t{
\t\treturn this.x[0];
\t}
\telse if (this.isEdge())
\t{
\t\treturn this.x[layer - this.minRank - 1];
\t}

\treturn 0.0;
};

/**
 * Function: setY
 * 
 * Set the value of y for the specified layer
 */
mxGraphAbstractHierarchyCell.prototype.setY = function(layer, value)
{
\tif (this.isVertex())
\t{
\t\tthis.y[0] = value;
\t}
\telse if (this.isEdge())
\t{
\t\tthis.y[layer -this. minRank - 1] = value;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphHierarchyNode
 * 
 * An abstraction of a hierarchical edge for the hierarchy layout
 * 
 * Constructor: mxGraphHierarchyNode
 *
 * Constructs an internal node to represent the specified real graph cell
 *
 * Arguments:
 * 
 * cell - the real graph cell this node represents
 */
function mxGraphHierarchyNode(cell)
{
\tmxGraphAbstractHierarchyCell.apply(this, arguments);
\tthis.cell = cell;
\tthis.id = mxObjectIdentity.get(cell);
\tthis.connectsAsTarget = [];
\tthis.connectsAsSource = [];
};

/**
 * Extends mxGraphAbstractHierarchyCell.
 */
mxGraphHierarchyNode.prototype = new mxGraphAbstractHierarchyCell();
mxGraphHierarchyNode.prototype.constructor = mxGraphHierarchyNode;

/**
 * Variable: cell
 * 
 * The graph cell this object represents.
 */
mxGraphHierarchyNode.prototype.cell = null;

/**
 * Variable: id
 * 
 * The object identity of the wrapped cell
 */
mxGraphHierarchyNode.prototype.id = null;

/**
 * Variable: connectsAsTarget
 * 
 * Collection of hierarchy edges that have this node as a target
 */
mxGraphHierarchyNode.prototype.connectsAsTarget = null;

/**
 * Variable: connectsAsSource
 * 
 * Collection of hierarchy edges that have this node as a source
 */
mxGraphHierarchyNode.prototype.connectsAsSource = null;

/**
 * Variable: hashCode
 * 
 * Assigns a unique hashcode for each node. Used by the model dfs instead
 * of copying HashSets
 */
mxGraphHierarchyNode.prototype.hashCode = false;

/**
 * Function: getRankValue
 * 
 * Returns the integer value of the layer that this node resides in
 */
mxGraphHierarchyNode.prototype.getRankValue = function(layer)
{
\treturn this.maxRank;
};

/**
 * Function: getNextLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer up
 */
mxGraphHierarchyNode.prototype.getNextLayerConnectedCells = function(layer)
{
\tif (this.nextLayerConnectedCells == null)
\t{
\t\tthis.nextLayerConnectedCells = [];
\t\tthis.nextLayerConnectedCells[0] = [];
\t\t
\t\tfor (var i = 0; i < this.connectsAsTarget.length; i++)
\t\t{
\t\t\tvar edge = this.connectsAsTarget[i];

\t\t\tif (edge.maxRank == -1 || edge.maxRank == layer + 1)
\t\t\t{
\t\t\t\t// Either edge is not in any rank or
\t\t\t\t// no dummy nodes in edge, add node of other side of edge
\t\t\t\tthis.nextLayerConnectedCells[0].push(edge.source);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Edge spans at least two layers, add edge
\t\t\t\tthis.nextLayerConnectedCells[0].push(edge);
\t\t\t}
\t\t}
\t}

\treturn this.nextLayerConnectedCells[0];
};

/**
 * Function: getPreviousLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer down
 */
mxGraphHierarchyNode.prototype.getPreviousLayerConnectedCells = function(layer)
{
\tif (this.previousLayerConnectedCells == null)
\t{
\t\tthis.previousLayerConnectedCells = [];
\t\tthis.previousLayerConnectedCells[0] = [];
\t\t
\t\tfor (var i = 0; i < this.connectsAsSource.length; i++)
\t\t{
\t\t\tvar edge = this.connectsAsSource[i];

\t\t\tif (edge.minRank == -1 || edge.minRank == layer - 1)
\t\t\t{
\t\t\t\t// No dummy nodes in edge, add node of other side of edge
\t\t\t\tthis.previousLayerConnectedCells[0].push(edge.target);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Edge spans at least two layers, add edge
\t\t\t\tthis.previousLayerConnectedCells[0].push(edge);
\t\t\t}
\t\t}
\t}

\treturn this.previousLayerConnectedCells[0];
};

/**
 * Function: isVertex
 * 
 * Returns true.
 */
mxGraphHierarchyNode.prototype.isVertex = function()
{
\treturn true;
};

/**
 * Function: getGeneralPurposeVariable
 * 
 * Gets the value of temp for the specified layer
 */
mxGraphHierarchyNode.prototype.getGeneralPurposeVariable = function(layer)
{
\treturn this.temp[0];
};

/**
 * Function: setGeneralPurposeVariable
 * 
 * Set the value of temp for the specified layer
 */
mxGraphHierarchyNode.prototype.setGeneralPurposeVariable = function(layer, value)
{
\tthis.temp[0] = value;
};

/**
 * Function: isAncestor
 */
mxGraphHierarchyNode.prototype.isAncestor = function(otherNode)
{
\t// Firstly, the hash code of this node needs to be shorter than the
\t// other node
\tif (otherNode != null && this.hashCode != null && otherNode.hashCode != null
\t\t\t&& this.hashCode.length < otherNode.hashCode.length)
\t{
\t\tif (this.hashCode == otherNode.hashCode)
\t\t{
\t\t\treturn true;
\t\t}
\t\t
\t\tif (this.hashCode == null || this.hashCode == null)
\t\t{
\t\t\treturn false;
\t\t}
\t\t
\t\t// Secondly, this hash code must match the start of the other
\t\t// node's hash code. Arrays.equals cannot be used here since
\t\t// the arrays are different length, and we do not want to
\t\t// perform another array copy.
\t\tfor (var i = 0; i < this.hashCode.length; i++)
\t\t{
\t\t\tif (this.hashCode[i] != otherNode.hashCode[i])
\t\t\t{
\t\t\t\treturn false;
\t\t\t}
\t\t}

\t\treturn true;
\t}

\treturn false;
};

/**
 * Function: getCoreCell
 * 
 * Gets the core vertex associated with this wrapper
 */
mxGraphHierarchyNode.prototype.getCoreCell = function()
{
\treturn this.cell;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphHierarchyEdge
 * 
 * An abstraction of a hierarchical edge for the hierarchy layout
 * 
 * Constructor: mxGraphHierarchyEdge
 *
 * Constructs a hierarchy edge
 *
 * Arguments:
 * 
 * edges - a list of real graph edges this abstraction represents
 */
function mxGraphHierarchyEdge(edges)
{
\tmxGraphAbstractHierarchyCell.apply(this, arguments);
\tthis.edges = edges;
\tthis.ids = [];
\t
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tthis.ids.push(mxObjectIdentity.get(edges[i]));
\t}
};

/**
 * Extends mxGraphAbstractHierarchyCell.
 */
mxGraphHierarchyEdge.prototype = new mxGraphAbstractHierarchyCell();
mxGraphHierarchyEdge.prototype.constructor = mxGraphHierarchyEdge;

/**
 * Variable: edges
 * 
 * The graph edge(s) this object represents. Parallel edges are all grouped
 * together within one hierarchy edge.
 */
mxGraphHierarchyEdge.prototype.edges = null;

/**
 * Variable: ids
 * 
 * The object identities of the wrapped cells
 */
mxGraphHierarchyEdge.prototype.ids = null;

/**
 * Variable: source
 * 
 * The node this edge is sourced at
 */
mxGraphHierarchyEdge.prototype.source = null;

/**
 * Variable: target
 * 
 * The node this edge targets
 */
mxGraphHierarchyEdge.prototype.target = null;

/**
 * Variable: isReversed
 * 
 * Whether or not the direction of this edge has been reversed
 * internally to create a DAG for the hierarchical layout
 */
mxGraphHierarchyEdge.prototype.isReversed = false;

/**
 * Function: invert
 * 
 * Inverts the direction of this internal edge(s)
 */
mxGraphHierarchyEdge.prototype.invert = function(layer)
{
\tvar temp = this.source;
\tthis.source = this.target;
\tthis.target = temp;
\tthis.isReversed = !this.isReversed;
};

/**
 * Function: getNextLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer up
 */
mxGraphHierarchyEdge.prototype.getNextLayerConnectedCells = function(layer)
{
\tif (this.nextLayerConnectedCells == null)
\t{
\t\tthis.nextLayerConnectedCells = [];
\t\t
\t\tfor (var i = 0; i < this.temp.length; i++)
\t\t{
\t\t\tthis.nextLayerConnectedCells[i] = [];
\t\t\t
\t\t\tif (i == this.temp.length - 1)
\t\t\t{
\t\t\t\tthis.nextLayerConnectedCells[i].push(this.source);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.nextLayerConnectedCells[i].push(this);
\t\t\t}
\t\t}
\t}
\t
\treturn this.nextLayerConnectedCells[layer - this.minRank - 1];
};

/**
 * Function: getPreviousLayerConnectedCells
 * 
 * Returns the cells this cell connects to on the next layer down
 */
mxGraphHierarchyEdge.prototype.getPreviousLayerConnectedCells = function(layer)
{
\tif (this.previousLayerConnectedCells == null)
\t{
\t\tthis.previousLayerConnectedCells = [];

\t\tfor (var i = 0; i < this.temp.length; i++)
\t\t{
\t\t\tthis.previousLayerConnectedCells[i] = [];
\t\t\t
\t\t\tif (i == 0)
\t\t\t{
\t\t\t\tthis.previousLayerConnectedCells[i].push(this.target);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.previousLayerConnectedCells[i].push(this);
\t\t\t}
\t\t}
\t}

\treturn this.previousLayerConnectedCells[layer - this.minRank - 1];
};

/**
 * Function: isEdge
 * 
 * Returns true.
 */
mxGraphHierarchyEdge.prototype.isEdge = function()
{
\treturn true;
};

/**
 * Function: getGeneralPurposeVariable
 * 
 * Gets the value of temp for the specified layer
 */
mxGraphHierarchyEdge.prototype.getGeneralPurposeVariable = function(layer)
{
\treturn this.temp[layer - this.minRank - 1];
};

/**
 * Function: setGeneralPurposeVariable
 * 
 * Set the value of temp for the specified layer
 */
mxGraphHierarchyEdge.prototype.setGeneralPurposeVariable = function(layer, value)
{
\tthis.temp[layer - this.minRank - 1] = value;
};

/**
 * Function: getCoreCell
 * 
 * Gets the first core edge associated with this wrapper
 */
mxGraphHierarchyEdge.prototype.getCoreCell = function()
{
\tif (this.edges != null && this.edges.length > 0)
\t{
\t\treturn this.edges[0];
\t}
\t
\treturn null;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphHierarchyModel
 *
 * Internal model of a hierarchical graph. This model stores nodes and edges
 * equivalent to the real graph nodes and edges, but also stores the rank of the
 * cells, the order within the ranks and the new candidate locations of cells.
 * The internal model also reverses edge direction were appropriate , ignores
 * self-loop and groups parallels together under one edge object.
 *
 * Constructor: mxGraphHierarchyModel
 *
 * Creates an internal ordered graph model using the vertices passed in. If
 * there are any, leftward edge need to be inverted in the internal model
 *
 * Arguments:
 *
 * graph - the facade describing the graph to be operated on
 * vertices - the vertices for this hierarchy
 * ordered - whether or not the vertices are already ordered
 * deterministic - whether or not this layout should be deterministic on each
 * tightenToSource - whether or not to tighten vertices towards the sources
 * scanRanksFromSinks - Whether rank assignment is from the sinks or sources.
 * usage
 */
function mxGraphHierarchyModel(layout, vertices, roots, parent, tightenToSource)
{
\tvar graph = layout.getGraph();
\tthis.tightenToSource = tightenToSource;
\tthis.roots = roots;
\tthis.parent = parent;

\t// map of cells to internal cell needed for second run through
\t// to setup the sink of edges correctly
\tthis.vertexMapper = new mxDictionary();
\tthis.edgeMapper = new mxDictionary();
\tthis.maxRank = 0;
\tvar internalVertices = [];

\tif (vertices == null)
\t{
\t\tvertices = this.graph.getChildVertices(parent);
\t}

\tthis.maxRank = this.SOURCESCANSTARTRANK;
\t// map of cells to internal cell needed for second run through
\t// to setup the sink of edges correctly. Guess size by number
\t// of edges is roughly same as number of vertices.
\tthis.createInternalCells(layout, vertices, internalVertices);

\t// Go through edges set their sink values. Also check the
\t// ordering if and invert edges if necessary
\tfor (var i = 0; i < vertices.length; i++)
\t{
\t\tvar edges = internalVertices[i].connectsAsSource;

\t\tfor (var j = 0; j < edges.length; j++)
\t\t{
\t\t\tvar internalEdge = edges[j];
\t\t\tvar realEdges = internalEdge.edges;

\t\t\t// Only need to process the first real edge, since
\t\t\t// all the edges connect to the same other vertex
\t\t\tif (realEdges != null && realEdges.length > 0)
\t\t\t{
\t\t\t\tvar realEdge = realEdges[0];
\t\t\t\tvar targetCell = layout.getVisibleTerminal(
\t\t\t\t\t\trealEdge, false);
\t\t\t\tvar internalTargetCell = this.vertexMapper.get(targetCell);

\t\t\t\tif (internalVertices[i] == internalTargetCell)
\t\t\t\t{
\t\t\t\t\t// If there are parallel edges going between two vertices and not all are in the same direction
\t\t\t\t\t// you can have navigated across one direction when doing the cycle reversal that isn't the same
\t\t\t\t\t// direction as the first real edge in the array above. When that happens the if above catches
\t\t\t\t\t// that and we correct the target cell before continuing.
\t\t\t\t\t// This branch only detects this single case
\t\t\t\t\ttargetCell = layout.getVisibleTerminal(
\t\t\t\t\t\t\trealEdge, true);
\t\t\t\t\tinternalTargetCell = this.vertexMapper.get(targetCell);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (internalTargetCell != null
\t\t\t\t\t\t&& internalVertices[i] != internalTargetCell)
\t\t\t\t{
\t\t\t\t\tinternalEdge.target = internalTargetCell;

\t\t\t\t\tif (internalTargetCell.connectsAsTarget.length == 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalTargetCell.connectsAsTarget = [];
\t\t\t\t\t}

\t\t\t\t\tif (mxUtils.indexOf(internalTargetCell.connectsAsTarget, internalEdge) < 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalTargetCell.connectsAsTarget.push(internalEdge);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Use the temp variable in the internal nodes to mark this
\t\t// internal vertex as having been visited.
\t\tinternalVertices[i].temp[0] = 1;
\t}
};

/**
 * Variable: maxRank
 *
 * Stores the largest rank number allocated
 */
mxGraphHierarchyModel.prototype.maxRank = null;

/**
 * Variable: vertexMapper
 *
 * Map from graph vertices to internal model nodes.
 */
mxGraphHierarchyModel.prototype.vertexMapper = null;

/**
 * Variable: edgeMapper
 *
 * Map from graph edges to internal model edges
 */
mxGraphHierarchyModel.prototype.edgeMapper = null;

/**
 * Variable: ranks
 *
 * Mapping from rank number to actual rank
 */
mxGraphHierarchyModel.prototype.ranks = null;

/**
 * Variable: roots
 *
 * Store of roots of this hierarchy model, these are real graph cells, not
 * internal cells
 */
mxGraphHierarchyModel.prototype.roots = null;

/**
 * Variable: parent
 *
 * The parent cell whose children are being laid out
 */
mxGraphHierarchyModel.prototype.parent = null;

/**
 * Variable: dfsCount
 *
 * Count of the number of times the ancestor dfs has been used.
 */
mxGraphHierarchyModel.prototype.dfsCount = 0;

/**
 * Variable: SOURCESCANSTARTRANK
 *
 * High value to start source layering scan rank value from.
 */
mxGraphHierarchyModel.prototype.SOURCESCANSTARTRANK = 100000000;

/**
 * Variable: tightenToSource
 *
 * Whether or not to tighten the assigned ranks of vertices up towards
 * the source cells.
 */
mxGraphHierarchyModel.prototype.tightenToSource = false;

/**
 * Function: createInternalCells
 *
 * Creates all edges in the internal model
 *
 * Parameters:
 *
 * layout - Reference to the <mxHierarchicalLayout> algorithm.
 * vertices - Array of <mxCells> that represent the vertices whom are to
 * have an internal representation created.
 * internalVertices - The array of <mxGraphHierarchyNodes> to have their
 * information filled in using the real vertices.
 */
mxGraphHierarchyModel.prototype.createInternalCells = function(layout, vertices, internalVertices)
{
\tvar graph = layout.getGraph();

\t// Create internal edges
\tfor (var i = 0; i < vertices.length; i++)
\t{
\t\tinternalVertices[i] = new mxGraphHierarchyNode(vertices[i]);
\t\tthis.vertexMapper.put(vertices[i], internalVertices[i]);

\t\t// If the layout is deterministic, order the cells
\t\t//List outgoingCells = graph.getNeighbours(vertices[i], deterministic);
\t\tvar conns = layout.getEdges(vertices[i]);
\t\tinternalVertices[i].connectsAsSource = [];

\t\t// Create internal edges, but don't do any rank assignment yet
\t\t// First use the information from the greedy cycle remover to
\t\t// invert the leftward edges internally
\t\tfor (var j = 0; j < conns.length; j++)
\t\t{
\t\t\tvar cell = layout.getVisibleTerminal(conns[j], false);

\t\t\t// Looking for outgoing edges only
\t\t\tif (cell != vertices[i] && layout.graph.model.isVertex(cell) &&
\t\t\t\t\t!layout.isVertexIgnored(cell))
\t\t\t{
\t\t\t\t// We process all edge between this source and its targets
\t\t\t\t// If there are edges going both ways, we need to collect
\t\t\t\t// them all into one internal edges to avoid looping problems
\t\t\t\t// later. We assume this direction (source -> target) is the 
\t\t\t\t// natural direction if at least half the edges are going in
\t\t\t\t// that direction.

\t\t\t\t// The check below for edges[0] being in the vertex mapper is
\t\t\t\t// in case we've processed this the other way around
\t\t\t\t// (target -> source) and the number of edges in each direction
\t\t\t\t// are the same. All the graph edges will have been assigned to
\t\t\t\t// an internal edge going the other way, so we don't want to 
\t\t\t\t// process them again
\t\t\t\tvar undirectedEdges = layout.getEdgesBetween(vertices[i],
\t\t\t\t\t\tcell, false);
\t\t\t\tvar directedEdges = layout.getEdgesBetween(vertices[i],
\t\t\t\t\t\tcell, true);
\t\t\t\t
\t\t\t\tif (undirectedEdges != null &&
\t\t\t\t\t\tundirectedEdges.length > 0 &&
\t\t\t\t\t\tthis.edgeMapper.get(undirectedEdges[0]) == null &&
\t\t\t\t\t\tdirectedEdges.length * 2 >= undirectedEdges.length)
\t\t\t\t{
\t\t\t\t\tvar internalEdge = new mxGraphHierarchyEdge(undirectedEdges);

\t\t\t\t\tfor (var k = 0; k < undirectedEdges.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tvar edge = undirectedEdges[k];
\t\t\t\t\t\tthis.edgeMapper.put(edge, internalEdge);

\t\t\t\t\t\t// Resets all point on the edge and disables the edge style
\t\t\t\t\t\t// without deleting it from the cell style
\t\t\t\t\t\tgraph.resetEdge(edge);

\t\t\t\t\t    if (layout.disableEdgeStyle)
\t\t\t\t\t    {
\t\t\t\t\t    \tlayout.setEdgeStyleEnabled(edge, false);
\t\t\t\t\t    \tlayout.setOrthogonalEdge(edge,true);
\t\t\t\t\t    }
\t\t\t\t\t}

\t\t\t\t\tinternalEdge.source = internalVertices[i];

\t\t\t\t\tif (mxUtils.indexOf(internalVertices[i].connectsAsSource, internalEdge) < 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalVertices[i].connectsAsSource.push(internalEdge);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Ensure temp variable is cleared from any previous use
\t\tinternalVertices[i].temp[0] = 0;
\t}
};

/**
 * Function: initialRank
 *
 * Basic determination of minimum layer ranking by working from from sources
 * or sinks and working through each node in the relevant edge direction.
 * Starting at the sinks is basically a longest path layering algorithm.
*/
mxGraphHierarchyModel.prototype.initialRank = function()
{
\tvar startNodes = [];

\tif (this.roots != null)
\t{
\t\tfor (var i = 0; i < this.roots.length; i++)
\t\t{
\t\t\tvar internalNode = this.vertexMapper.get(this.roots[i]);

\t\t\tif (internalNode != null)
\t\t\t{
\t\t\t\tstartNodes.push(internalNode);
\t\t\t}
\t\t}
\t}

\tvar internalNodes = this.vertexMapper.getValues();
\t
\tfor (var i=0; i < internalNodes.length; i++)
\t{
\t\t// Mark the node as not having had a layer assigned
\t\tinternalNodes[i].temp[0] = -1;
\t}

\tvar startNodesCopy = startNodes.slice();

\twhile (startNodes.length > 0)
\t{
\t\tvar internalNode = startNodes[0];
\t\tvar layerDeterminingEdges;
\t\tvar edgesToBeMarked;

\t\tlayerDeterminingEdges = internalNode.connectsAsTarget;
\t\tedgesToBeMarked = internalNode.connectsAsSource;

\t\t// flag to keep track of whether or not all layer determining
\t\t// edges have been scanned
\t\tvar allEdgesScanned = true;

\t\t// Work out the layer of this node from the layer determining
\t\t// edges. The minimum layer number of any node connected by one of
\t\t// the layer determining edges variable
\t\tvar minimumLayer = this.SOURCESCANSTARTRANK;

\t\tfor (var i = 0; i < layerDeterminingEdges.length; i++)
\t\t{
\t\t\tvar internalEdge = layerDeterminingEdges[i];

\t\t\tif (internalEdge.temp[0] == 5270620)
\t\t\t{
\t\t\t\t// This edge has been scanned, get the layer of the
\t\t\t\t// node on the other end
\t\t\t\tvar otherNode = internalEdge.source;
\t\t\t\tminimumLayer = Math.min(minimumLayer, otherNode.temp[0] - 1);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tallEdgesScanned = false;

\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\t// If all edge have been scanned, assign the layer, mark all
\t\t// edges in the other direction and remove from the nodes list
\t\tif (allEdgesScanned)
\t\t{
\t\t\tinternalNode.temp[0] = minimumLayer;
\t\t\tthis.maxRank = Math.min(this.maxRank, minimumLayer);

\t\t\tif (edgesToBeMarked != null)
\t\t\t{
\t\t\t\tfor (var i = 0; i < edgesToBeMarked.length; i++)
\t\t\t\t{
\t\t\t\t\tvar internalEdge = edgesToBeMarked[i];

\t\t\t\t\t// Assign unique stamp ( y/m/d/h )
\t\t\t\t\tinternalEdge.temp[0] = 5270620;

\t\t\t\t\t// Add node on other end of edge to LinkedList of
\t\t\t\t\t// nodes to be analysed
\t\t\t\t\tvar otherNode = internalEdge.target;

\t\t\t\t\t// Only add node if it hasn't been assigned a layer
\t\t\t\t\tif (otherNode.temp[0] == -1)
\t\t\t\t\t{
\t\t\t\t\t\tstartNodes.push(otherNode);

\t\t\t\t\t\t// Mark this other node as neither being
\t\t\t\t\t\t// unassigned nor assigned so it isn't
\t\t\t\t\t\t// added to this list again, but it's
\t\t\t\t\t\t// layer isn't used in any calculation.
\t\t\t\t\t\totherNode.temp[0] = -2;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tstartNodes.shift();
\t\t}
\t\telse
\t\t{
\t\t\t// Not all the edges have been scanned, get to the back of
\t\t\t// the class and put the dunces cap on
\t\t\tvar removedCell = startNodes.shift();
\t\t\tstartNodes.push(internalNode);

\t\t\tif (removedCell == internalNode && startNodes.length == 1)
\t\t\t{
\t\t\t\t// This is an error condition, we can't get out of
\t\t\t\t// this loop. It could happen for more than one node
\t\t\t\t// but that's a lot harder to detect. Log the error
\t\t\t\t// TODO make log comment
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t}

\t// Normalize the ranks down from their large starting value to place
\t// at least 1 sink on layer 0
\tfor (var i=0; i < internalNodes.length; i++)
\t{
\t\t// Mark the node as not having had a layer assigned
\t\tinternalNodes[i].temp[0] -= this.maxRank;
\t}
\t
\t// Tighten the rank 0 nodes as far as possible
\tfor ( var i = 0; i < startNodesCopy.length; i++)
\t{
\t\tvar internalNode = startNodesCopy[i];
\t\tvar currentMaxLayer = 0;
\t\tvar layerDeterminingEdges = internalNode.connectsAsSource;

\t\tfor ( var j = 0; j < layerDeterminingEdges.length; j++)
\t\t{
\t\t\tvar internalEdge = layerDeterminingEdges[j];
\t\t\tvar otherNode = internalEdge.target;
\t\t\tinternalNode.temp[0] = Math.max(currentMaxLayer,
\t\t\t\t\totherNode.temp[0] + 1);
\t\t\tcurrentMaxLayer = internalNode.temp[0];
\t\t}
\t}
\t
\t// Reset the maxRank to that which would be expected for a from-sink
\t// scan
\tthis.maxRank = this.SOURCESCANSTARTRANK - this.maxRank;
};

/**
 * Function: fixRanks
 *
 * Fixes the layer assignments to the values stored in the nodes. Also needs
 * to create dummy nodes for edges that cross layers.
 */
mxGraphHierarchyModel.prototype.fixRanks = function()
{
\tvar rankList = [];
\tthis.ranks = [];

\tfor (var i = 0; i < this.maxRank + 1; i++)
\t{
\t\trankList[i] = [];
\t\tthis.ranks[i] = rankList[i];
\t}

\t// Perform a DFS to obtain an initial ordering for each rank.
\t// Without doing this you would end up having to process
\t// crossings for a standard tree.
\tvar rootsArray = null;

\tif (this.roots != null)
\t{
\t\tvar oldRootsArray = this.roots;
\t\trootsArray = [];

\t\tfor (var i = 0; i < oldRootsArray.length; i++)
\t\t{
\t\t\tvar cell = oldRootsArray[i];
\t\t\tvar internalNode = this.vertexMapper.get(cell);
\t\t\trootsArray[i] = internalNode;
\t\t}
\t}

\tthis.visit(function(parent, node, edge, layer, seen)
\t{
\t\tif (seen == 0 && node.maxRank < 0 && node.minRank < 0)
\t\t{
\t\t\trankList[node.temp[0]].push(node);
\t\t\tnode.maxRank = node.temp[0];
\t\t\tnode.minRank = node.temp[0];

\t\t\t// Set temp[0] to the nodes position in the rank
\t\t\tnode.temp[0] = rankList[node.maxRank].length - 1;
\t\t}

\t\tif (parent != null && edge != null)
\t\t{
\t\t\tvar parentToCellRankDifference = parent.maxRank - node.maxRank;

\t\t\tif (parentToCellRankDifference > 1)
\t\t\t{
\t\t\t\t// There are ranks in between the parent and current cell
\t\t\t\tedge.maxRank = parent.maxRank;
\t\t\t\tedge.minRank = node.maxRank;
\t\t\t\tedge.temp = [];
\t\t\t\tedge.x = [];
\t\t\t\tedge.y = [];

\t\t\t\tfor (var i = edge.minRank + 1; i < edge.maxRank; i++)
\t\t\t\t{
\t\t\t\t\t// The connecting edge must be added to the
\t\t\t\t\t// appropriate ranks
\t\t\t\t\trankList[i].push(edge);
\t\t\t\t\tedge.setGeneralPurposeVariable(i, rankList[i]
\t\t\t\t\t\t\t.length - 1);
\t\t\t\t}
\t\t\t}
\t\t}
\t}, rootsArray, false, null);
};

/**
 * Function: visit
 *
 * A depth first search through the internal heirarchy model.
 *
 * Parameters:
 *
 * visitor - The visitor function pattern to be called for each node.
 * trackAncestors - Whether or not the search is to keep track all nodes
 * directly above this one in the search path.
 */
mxGraphHierarchyModel.prototype.visit = function(visitor, dfsRoots, trackAncestors, seenNodes)
{
\t// Run dfs through on all roots
\tif (dfsRoots != null)
\t{
\t\tfor (var i = 0; i < dfsRoots.length; i++)
\t\t{
\t\t\tvar internalNode = dfsRoots[i];

\t\t\tif (internalNode != null)
\t\t\t{
\t\t\t\tif (seenNodes == null)
\t\t\t\t{
\t\t\t\t\tseenNodes = new Object();
\t\t\t\t}

\t\t\t\tif (trackAncestors)
\t\t\t\t{
\t\t\t\t\t// Set up hash code for root
\t\t\t\t\tinternalNode.hashCode = [];
\t\t\t\t\tinternalNode.hashCode[0] = this.dfsCount;
\t\t\t\t\tinternalNode.hashCode[1] = i;
\t\t\t\t\tthis.extendedDfs(null, internalNode, null, visitor, seenNodes,
\t\t\t\t\t\t\tinternalNode.hashCode, i, 0);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.dfs(null, internalNode, null, visitor, seenNodes, 0);
\t\t\t\t}
\t\t\t}
\t\t}

\t\tthis.dfsCount++;
\t}
};

/**
 * Function: dfs
 *
 * Performs a depth first search on the internal hierarchy model
 *
 * Parameters:
 *
 * parent - the parent internal node of the current internal node
 * root - the current internal node
 * connectingEdge - the internal edge connecting the internal node and the parent
 * internal node, if any
 * visitor - the visitor pattern to be called for each node
 * seen - a set of all nodes seen by this dfs a set of all of the
 * ancestor node of the current node
 * layer - the layer on the dfs tree ( not the same as the model ranks )
 */
mxGraphHierarchyModel.prototype.dfs = function(parent, root, connectingEdge, visitor, seen, layer)
{
\tif (root != null)
\t{
\t\tvar rootId = root.id;

\t\tif (seen[rootId] == null)
\t\t{
\t\t\tseen[rootId] = root;
\t\t\tvisitor(parent, root, connectingEdge, layer, 0);

\t\t\t// Copy the connects as source list so that visitors
\t\t\t// can change the original for edge direction inversions
\t\t\tvar outgoingEdges = root.connectsAsSource.slice();
\t\t\t
\t\t\tfor (var i = 0; i< outgoingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = outgoingEdges[i];
\t\t\t\tvar targetNode = internalEdge.target;

\t\t\t\t// Root check is O(|roots|)
\t\t\t\tthis.dfs(root, targetNode, internalEdge, visitor, seen,
\t\t\t\t\t\tlayer + 1);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Use the int field to indicate this node has been seen
\t\t\tvisitor(parent, root, connectingEdge, layer, 1);
\t\t}
\t}
};

/**
 * Function: extendedDfs
 *
 * Performs a depth first search on the internal hierarchy model. This dfs
 * extends the default version by keeping track of cells ancestors, but it
 * should be only used when necessary because of it can be computationally
 * intensive for deep searches.
 *
 * Parameters:
 *
 * parent - the parent internal node of the current internal node
 * root - the current internal node
 * connectingEdge - the internal edge connecting the internal node and the parent
 * internal node, if any
 * visitor - the visitor pattern to be called for each node
 * seen - a set of all nodes seen by this dfs
 * ancestors - the parent hash code
 * childHash - the new hash code for this node
 * layer - the layer on the dfs tree ( not the same as the model ranks )
 */
mxGraphHierarchyModel.prototype.extendedDfs = function(parent, root, connectingEdge, visitor, seen, ancestors, childHash, layer)
{
\t// Explanation of custom hash set. Previously, the ancestors variable
\t// was passed through the dfs as a HashSet. The ancestors were copied
\t// into a new HashSet and when the new child was processed it was also
\t// added to the set. If the current node was in its ancestor list it
\t// meant there is a cycle in the graph and this information is passed
\t// to the visitor.visit() in the seen parameter. The HashSet clone was
\t// very expensive on CPU so a custom hash was developed using primitive
\t// types. temp[] couldn't be used so hashCode[] was added to each node.
\t// Each new child adds another int to the array, copying the prefix
\t// from its parent. Child of the same parent add different ints (the
\t// limit is therefore 2^32 children per parent...). If a node has a
\t// child with the hashCode already set then the child code is compared
\t// to the same portion of the current nodes array. If they match there
\t// is a loop.
\t// Note that the basic mechanism would only allow for 1 use of this
\t// functionality, so the root nodes have two ints. The second int is
\t// incremented through each node root and the first is incremented
\t// through each run of the dfs algorithm (therefore the dfs is not
\t// thread safe). The hash code of each node is set if not already set,
\t// or if the first int does not match that of the current run.
\tif (root != null)
\t{
\t\tif (parent != null)
\t\t{
\t\t\t// Form this nodes hash code if necessary, that is, if the
\t\t\t// hashCode variable has not been initialized or if the
\t\t\t// start of the parent hash code does not equal the start of
\t\t\t// this nodes hash code, indicating the code was set on a
\t\t\t// previous run of this dfs.
\t\t\tif (root.hashCode == null ||
\t\t\t\troot.hashCode[0] != parent.hashCode[0])
\t\t\t{
\t\t\t\tvar hashCodeLength = parent.hashCode.length + 1;
\t\t\t\troot.hashCode = parent.hashCode.slice();
\t\t\t\troot.hashCode[hashCodeLength - 1] = childHash;
\t\t\t}
\t\t}

\t\tvar rootId = root.id;

\t\tif (seen[rootId] == null)
\t\t{
\t\t\tseen[rootId] = root;
\t\t\tvisitor(parent, root, connectingEdge, layer, 0);

\t\t\t// Copy the connects as source list so that visitors
\t\t\t// can change the original for edge direction inversions
\t\t\tvar outgoingEdges = root.connectsAsSource.slice();

\t\t\tfor (var i = 0; i < outgoingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = outgoingEdges[i];
\t\t\t\tvar targetNode = internalEdge.target;

\t\t\t\t// Root check is O(|roots|)
\t\t\t\tthis.extendedDfs(root, targetNode, internalEdge, visitor, seen,
\t\t\t\t\t\troot.hashCode, i, layer + 1);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Use the int field to indicate this node has been seen
\t\t\tvisitor(parent, root, connectingEdge, layer, 1);
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxSwimlaneModel
 *
 * Internal model of a hierarchical graph. This model stores nodes and edges
 * equivalent to the real graph nodes and edges, but also stores the rank of the
 * cells, the order within the ranks and the new candidate locations of cells.
 * The internal model also reverses edge direction were appropriate , ignores
 * self-loop and groups parallels together under one edge object.
 *
 * Constructor: mxSwimlaneModel
 *
 * Creates an internal ordered graph model using the vertices passed in. If
 * there are any, leftward edge need to be inverted in the internal model
 *
 * Arguments:
 *
 * graph - the facade describing the graph to be operated on
 * vertices - the vertices for this hierarchy
 * ordered - whether or not the vertices are already ordered
 * deterministic - whether or not this layout should be deterministic on each
 * tightenToSource - whether or not to tighten vertices towards the sources
 * scanRanksFromSinks - Whether rank assignment is from the sinks or sources.
 * usage
 */
function mxSwimlaneModel(layout, vertices, roots, parent, tightenToSource)
{
\tvar graph = layout.getGraph();
\tthis.tightenToSource = tightenToSource;
\tthis.roots = roots;
\tthis.parent = parent;

\t// map of cells to internal cell needed for second run through
\t// to setup the sink of edges correctly
\tthis.vertexMapper = new mxDictionary();
\tthis.edgeMapper = new mxDictionary();
\tthis.maxRank = 0;
\tvar internalVertices = [];

\tif (vertices == null)
\t{
\t\tvertices = this.graph.getChildVertices(parent);
\t}

\tthis.maxRank = this.SOURCESCANSTARTRANK;
\t// map of cells to internal cell needed for second run through
\t// to setup the sink of edges correctly. Guess size by number
\t// of edges is roughly same as number of vertices.
\tthis.createInternalCells(layout, vertices, internalVertices);

\t// Go through edges set their sink values. Also check the
\t// ordering if and invert edges if necessary
\tfor (var i = 0; i < vertices.length; i++)
\t{
\t\tvar edges = internalVertices[i].connectsAsSource;

\t\tfor (var j = 0; j < edges.length; j++)
\t\t{
\t\t\tvar internalEdge = edges[j];
\t\t\tvar realEdges = internalEdge.edges;

\t\t\t// Only need to process the first real edge, since
\t\t\t// all the edges connect to the same other vertex
\t\t\tif (realEdges != null && realEdges.length > 0)
\t\t\t{
\t\t\t\tvar realEdge = realEdges[0];
\t\t\t\tvar targetCell = layout.getVisibleTerminal(
\t\t\t\t\t\trealEdge, false);
\t\t\t\tvar internalTargetCell = this.vertexMapper.get(targetCell);

\t\t\t\tif (internalVertices[i] == internalTargetCell)
\t\t\t\t{
\t\t\t\t\t// If there are parallel edges going between two vertices and not all are in the same direction
\t\t\t\t\t// you can have navigated across one direction when doing the cycle reversal that isn't the same
\t\t\t\t\t// direction as the first real edge in the array above. When that happens the if above catches
\t\t\t\t\t// that and we correct the target cell before continuing.
\t\t\t\t\t// This branch only detects this single case
\t\t\t\t\ttargetCell = layout.getVisibleTerminal(
\t\t\t\t\t\t\trealEdge, true);
\t\t\t\t\tinternalTargetCell = this.vertexMapper.get(targetCell);
\t\t\t\t}

\t\t\t\tif (internalTargetCell != null
\t\t\t\t\t\t&& internalVertices[i] != internalTargetCell)
\t\t\t\t{
\t\t\t\t\tinternalEdge.target = internalTargetCell;

\t\t\t\t\tif (internalTargetCell.connectsAsTarget.length == 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalTargetCell.connectsAsTarget = [];
\t\t\t\t\t}

\t\t\t\t\tif (mxUtils.indexOf(internalTargetCell.connectsAsTarget, internalEdge) < 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalTargetCell.connectsAsTarget.push(internalEdge);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Use the temp variable in the internal nodes to mark this
\t\t// internal vertex as having been visited.
\t\tinternalVertices[i].temp[0] = 1;
\t}
};

/**
 * Variable: maxRank
 *
 * Stores the largest rank number allocated
 */
mxSwimlaneModel.prototype.maxRank = null;

/**
 * Variable: vertexMapper
 *
 * Map from graph vertices to internal model nodes.
 */
mxSwimlaneModel.prototype.vertexMapper = null;

/**
 * Variable: edgeMapper
 *
 * Map from graph edges to internal model edges
 */
mxSwimlaneModel.prototype.edgeMapper = null;

/**
 * Variable: ranks
 *
 * Mapping from rank number to actual rank
 */
mxSwimlaneModel.prototype.ranks = null;

/**
 * Variable: roots
 *
 * Store of roots of this hierarchy model, these are real graph cells, not
 * internal cells
 */
mxSwimlaneModel.prototype.roots = null;

/**
 * Variable: parent
 *
 * The parent cell whose children are being laid out
 */
mxSwimlaneModel.prototype.parent = null;

/**
 * Variable: dfsCount
 *
 * Count of the number of times the ancestor dfs has been used.
 */
mxSwimlaneModel.prototype.dfsCount = 0;

/**
 * Variable: SOURCESCANSTARTRANK
 *
 * High value to start source layering scan rank value from.
 */
mxSwimlaneModel.prototype.SOURCESCANSTARTRANK = 100000000;

/**
 * Variable: tightenToSource
 *
 * Whether or not to tighten the assigned ranks of vertices up towards
 * the source cells.
 */
mxSwimlaneModel.prototype.tightenToSource = false;

/**
 * Variable: ranksPerGroup
 *
 * An array of the number of ranks within each swimlane
 */
mxSwimlaneModel.prototype.ranksPerGroup = null;

/**
 * Function: createInternalCells
 *
 * Creates all edges in the internal model
 *
 * Parameters:
 *
 * layout - Reference to the <mxHierarchicalLayout> algorithm.
 * vertices - Array of <mxCells> that represent the vertices whom are to
 * have an internal representation created.
 * internalVertices - The array of <mxGraphHierarchyNodes> to have their
 * information filled in using the real vertices.
 */
mxSwimlaneModel.prototype.createInternalCells = function(layout, vertices, internalVertices)
{
\tvar graph = layout.getGraph();
\tvar swimlanes = layout.swimlanes;

\t// Create internal edges
\tfor (var i = 0; i < vertices.length; i++)
\t{
\t\tinternalVertices[i] = new mxGraphHierarchyNode(vertices[i]);
\t\tthis.vertexMapper.put(vertices[i], internalVertices[i]);
\t\tinternalVertices[i].swimlaneIndex = -1;

\t\tfor (var ii = 0; ii < swimlanes.length; ii++)
\t\t{
\t\t\tif (graph.model.getParent(vertices[i]) == swimlanes[ii])
\t\t\t{
\t\t\t\tinternalVertices[i].swimlaneIndex = ii;
\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\t// If the layout is deterministic, order the cells
\t\t//List outgoingCells = graph.getNeighbours(vertices[i], deterministic);
\t\tvar conns = layout.getEdges(vertices[i]);
\t\tinternalVertices[i].connectsAsSource = [];

\t\t// Create internal edges, but don't do any rank assignment yet
\t\t// First use the information from the greedy cycle remover to
\t\t// invert the leftward edges internally
\t\tfor (var j = 0; j < conns.length; j++)
\t\t{
\t\t\tvar cell = layout.getVisibleTerminal(conns[j], false);

\t\t\t// Looking for outgoing edges only
\t\t\tif (cell != vertices[i] && layout.graph.model.isVertex(cell) &&
\t\t\t\t\t!layout.isVertexIgnored(cell))
\t\t\t{
\t\t\t\t// We process all edge between this source and its targets
\t\t\t\t// If there are edges going both ways, we need to collect
\t\t\t\t// them all into one internal edges to avoid looping problems
\t\t\t\t// later. We assume this direction (source -> target) is the 
\t\t\t\t// natural direction if at least half the edges are going in
\t\t\t\t// that direction.

\t\t\t\t// The check below for edges[0] being in the vertex mapper is
\t\t\t\t// in case we've processed this the other way around
\t\t\t\t// (target -> source) and the number of edges in each direction
\t\t\t\t// are the same. All the graph edges will have been assigned to
\t\t\t\t// an internal edge going the other way, so we don't want to 
\t\t\t\t// process them again
\t\t\t\tvar undirectedEdges = layout.getEdgesBetween(vertices[i],
\t\t\t\t\t\tcell, false);
\t\t\t\tvar directedEdges = layout.getEdgesBetween(vertices[i],
\t\t\t\t\t\tcell, true);
\t\t\t\t
\t\t\t\tif (undirectedEdges != null &&
\t\t\t\t\t\tundirectedEdges.length > 0 &&
\t\t\t\t\t\tthis.edgeMapper.get(undirectedEdges[0]) == null &&
\t\t\t\t\t\tdirectedEdges.length * 2 >= undirectedEdges.length)
\t\t\t\t{
\t\t\t\t\tvar internalEdge = new mxGraphHierarchyEdge(undirectedEdges);

\t\t\t\t\tfor (var k = 0; k < undirectedEdges.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tvar edge = undirectedEdges[k];
\t\t\t\t\t\tthis.edgeMapper.put(edge, internalEdge);

\t\t\t\t\t\t// Resets all point on the edge and disables the edge style
\t\t\t\t\t\t// without deleting it from the cell style
\t\t\t\t\t\tgraph.resetEdge(edge);

\t\t\t\t\t    if (layout.disableEdgeStyle)
\t\t\t\t\t    {
\t\t\t\t\t    \tlayout.setEdgeStyleEnabled(edge, false);
\t\t\t\t\t    \tlayout.setOrthogonalEdge(edge,true);
\t\t\t\t\t    }
\t\t\t\t\t}

\t\t\t\t\tinternalEdge.source = internalVertices[i];

\t\t\t\t\tif (mxUtils.indexOf(internalVertices[i].connectsAsSource, internalEdge) < 0)
\t\t\t\t\t{
\t\t\t\t\t\tinternalVertices[i].connectsAsSource.push(internalEdge);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Ensure temp variable is cleared from any previous use
\t\tinternalVertices[i].temp[0] = 0;
\t}
};

/**
 * Function: initialRank
 *
 * Basic determination of minimum layer ranking by working from from sources
 * or sinks and working through each node in the relevant edge direction.
 * Starting at the sinks is basically a longest path layering algorithm.
*/
mxSwimlaneModel.prototype.initialRank = function()
{
\tthis.ranksPerGroup = [];
\t
\tvar startNodes = [];
\tvar seen = new Object();

\tif (this.roots != null)
\t{
\t\tfor (var i = 0; i < this.roots.length; i++)
\t\t{
\t\t\tvar internalNode = this.vertexMapper.get(this.roots[i]);
\t\t\tthis.maxChainDfs(null, internalNode, null, seen, 0);

\t\t\tif (internalNode != null)
\t\t\t{
\t\t\t\tstartNodes.push(internalNode);
\t\t\t}
\t\t}
\t}

\t// Calculate the lower and upper rank bounds of each swimlane
\tvar lowerRank = [];
\tvar upperRank = [];
\t
\tfor (var i = this.ranksPerGroup.length - 1; i >= 0; i--)
\t{
\t\tif (i == this.ranksPerGroup.length - 1)
\t\t{
\t\t\tlowerRank[i] = 0;
\t\t}
\t\telse
\t\t{
\t\t\tlowerRank[i] = upperRank[i+1] + 1;
\t\t}
\t\t
\t\tupperRank[i] = lowerRank[i] + this.ranksPerGroup[i];
\t}
\t
\tthis.maxRank = upperRank[0];

\tvar internalNodes = this.vertexMapper.getValues();
\t
\tfor (var i=0; i < internalNodes.length; i++)
\t{
\t\t// Mark the node as not having had a layer assigned
\t\tinternalNodes[i].temp[0] = -1;
\t}

\tvar startNodesCopy = startNodes.slice();
\t
\twhile (startNodes.length > 0)
\t{
\t\tvar internalNode = startNodes[0];
\t\tvar layerDeterminingEdges;
\t\tvar edgesToBeMarked;

\t\tlayerDeterminingEdges = internalNode.connectsAsTarget;
\t\tedgesToBeMarked = internalNode.connectsAsSource;

\t\t// flag to keep track of whether or not all layer determining
\t\t// edges have been scanned
\t\tvar allEdgesScanned = true;

\t\t// Work out the layer of this node from the layer determining
\t\t// edges. The minimum layer number of any node connected by one of
\t\t// the layer determining edges variable
\t\tvar minimumLayer = upperRank[0];

\t\tfor (var i = 0; i < layerDeterminingEdges.length; i++)
\t\t{
\t\t\tvar internalEdge = layerDeterminingEdges[i];

\t\t\tif (internalEdge.temp[0] == 5270620)
\t\t\t{
\t\t\t\t// This edge has been scanned, get the layer of the
\t\t\t\t// node on the other end
\t\t\t\tvar otherNode = internalEdge.source;
\t\t\t\tminimumLayer = Math.min(minimumLayer, otherNode.temp[0] - 1);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tallEdgesScanned = false;

\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\t// If all edge have been scanned, assign the layer, mark all
\t\t// edges in the other direction and remove from the nodes list
\t\tif (allEdgesScanned)
\t\t{
\t\t\tif (minimumLayer > upperRank[internalNode.swimlaneIndex])
\t\t\t{
\t\t\t\tminimumLayer = upperRank[internalNode.swimlaneIndex];
\t\t\t}

\t\t\tinternalNode.temp[0] = minimumLayer;

\t\t\tif (edgesToBeMarked != null)
\t\t\t{
\t\t\t\tfor (var i = 0; i < edgesToBeMarked.length; i++)
\t\t\t\t{
\t\t\t\t\tvar internalEdge = edgesToBeMarked[i];

\t\t\t\t\t// Assign unique stamp ( y/m/d/h )
\t\t\t\t\tinternalEdge.temp[0] = 5270620;

\t\t\t\t\t// Add node on other end of edge to LinkedList of
\t\t\t\t\t// nodes to be analysed
\t\t\t\t\tvar otherNode = internalEdge.target;

\t\t\t\t\t// Only add node if it hasn't been assigned a layer
\t\t\t\t\tif (otherNode.temp[0] == -1)
\t\t\t\t\t{
\t\t\t\t\t\tstartNodes.push(otherNode);

\t\t\t\t\t\t// Mark this other node as neither being
\t\t\t\t\t\t// unassigned nor assigned so it isn't
\t\t\t\t\t\t// added to this list again, but it's
\t\t\t\t\t\t// layer isn't used in any calculation.
\t\t\t\t\t\totherNode.temp[0] = -2;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tstartNodes.shift();
\t\t}
\t\telse
\t\t{
\t\t\t// Not all the edges have been scanned, get to the back of
\t\t\t// the class and put the dunces cap on
\t\t\tvar removedCell = startNodes.shift();
\t\t\tstartNodes.push(internalNode);

\t\t\tif (removedCell == internalNode && startNodes.length == 1)
\t\t\t{
\t\t\t\t// This is an error condition, we can't get out of
\t\t\t\t// this loop. It could happen for more than one node
\t\t\t\t// but that's a lot harder to detect. Log the error
\t\t\t\t// TODO make log comment
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t}

\t// Normalize the ranks down from their large starting value to place
\t// at least 1 sink on layer 0
//\tfor (var key in this.vertexMapper)
//\t{
//\t\tvar internalNode = this.vertexMapper[key];
//\t\t// Mark the node as not having had a layer assigned
//\t\tinternalNode.temp[0] -= this.maxRank;
//\t}
\t
\t// Tighten the rank 0 nodes as far as possible
//\tfor ( var i = 0; i < startNodesCopy.length; i++)
//\t{
//\t\tvar internalNode = startNodesCopy[i];
//\t\tvar currentMaxLayer = 0;
//\t\tvar layerDeterminingEdges = internalNode.connectsAsSource;
//
//\t\tfor ( var j = 0; j < layerDeterminingEdges.length; j++)
//\t\t{
//\t\t\tvar internalEdge = layerDeterminingEdges[j];
//\t\t\tvar otherNode = internalEdge.target;
//\t\t\tinternalNode.temp[0] = Math.max(currentMaxLayer,
//\t\t\t\t\totherNode.temp[0] + 1);
//\t\t\tcurrentMaxLayer = internalNode.temp[0];
//\t\t}
//\t}
};

/**
 * Function: maxChainDfs
 *
 * Performs a depth first search on the internal hierarchy model. This dfs
 * extends the default version by keeping track of chains within groups.
 * Any cycles should be removed prior to running, but previously seen cells
 * are ignored.
 *
 * Parameters:
 *
 * parent - the parent internal node of the current internal node
 * root - the current internal node
 * connectingEdge - the internal edge connecting the internal node and the parent
 * internal node, if any
 * seen - a set of all nodes seen by this dfs
 * chainCount - the number of edges in the chain of vertices going through
 * the current swimlane
 */
mxSwimlaneModel.prototype.maxChainDfs = function(parent, root, connectingEdge, seen, chainCount)
{
\tif (root != null)
\t{
\t\tvar rootId = mxCellPath.create(root.cell);

\t\tif (seen[rootId] == null)
\t\t{
\t\t\tseen[rootId] = root;
\t\t\tvar slIndex = root.swimlaneIndex;
\t\t\t
\t\t\tif (this.ranksPerGroup[slIndex] == null || this.ranksPerGroup[slIndex] < chainCount)
\t\t\t{
\t\t\t\tthis.ranksPerGroup[slIndex] = chainCount;
\t\t\t}

\t\t\t// Copy the connects as source list so that visitors
\t\t\t// can change the original for edge direction inversions
\t\t\tvar outgoingEdges = root.connectsAsSource.slice();

\t\t\tfor (var i = 0; i < outgoingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = outgoingEdges[i];
\t\t\t\tvar targetNode = internalEdge.target;

\t\t\t\t// Only navigate in source->target direction within the same
\t\t\t\t// swimlane, or from a lower index swimlane to a higher one
\t\t\t\tif (root.swimlaneIndex < targetNode.swimlaneIndex)
\t\t\t\t{
\t\t\t\t\tthis.maxChainDfs(root, targetNode, internalEdge, mxUtils.clone(seen, null , true), 0);
\t\t\t\t}
\t\t\t\telse if (root.swimlaneIndex == targetNode.swimlaneIndex)
\t\t\t\t{
\t\t\t\t\tthis.maxChainDfs(root, targetNode, internalEdge, mxUtils.clone(seen, null , true), chainCount + 1);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: fixRanks
 *
 * Fixes the layer assignments to the values stored in the nodes. Also needs
 * to create dummy nodes for edges that cross layers.
 */
mxSwimlaneModel.prototype.fixRanks = function()
{
\tvar rankList = [];
\tthis.ranks = [];

\tfor (var i = 0; i < this.maxRank + 1; i++)
\t{
\t\trankList[i] = [];
\t\tthis.ranks[i] = rankList[i];
\t}

\t// Perform a DFS to obtain an initial ordering for each rank.
\t// Without doing this you would end up having to process
\t// crossings for a standard tree.
\tvar rootsArray = null;

\tif (this.roots != null)
\t{
\t\tvar oldRootsArray = this.roots;
\t\trootsArray = [];

\t\tfor (var i = 0; i < oldRootsArray.length; i++)
\t\t{
\t\t\tvar cell = oldRootsArray[i];
\t\t\tvar internalNode = this.vertexMapper.get(cell);
\t\t\trootsArray[i] = internalNode;
\t\t}
\t}

\tthis.visit(function(parent, node, edge, layer, seen)
\t{
\t\tif (seen == 0 && node.maxRank < 0 && node.minRank < 0)
\t\t{
\t\t\trankList[node.temp[0]].push(node);
\t\t\tnode.maxRank = node.temp[0];
\t\t\tnode.minRank = node.temp[0];

\t\t\t// Set temp[0] to the nodes position in the rank
\t\t\tnode.temp[0] = rankList[node.maxRank].length - 1;
\t\t}

\t\tif (parent != null && edge != null)
\t\t{
\t\t\tvar parentToCellRankDifference = parent.maxRank - node.maxRank;

\t\t\tif (parentToCellRankDifference > 1)
\t\t\t{
\t\t\t\t// There are ranks in between the parent and current cell
\t\t\t\tedge.maxRank = parent.maxRank;
\t\t\t\tedge.minRank = node.maxRank;
\t\t\t\tedge.temp = [];
\t\t\t\tedge.x = [];
\t\t\t\tedge.y = [];

\t\t\t\tfor (var i = edge.minRank + 1; i < edge.maxRank; i++)
\t\t\t\t{
\t\t\t\t\t// The connecting edge must be added to the
\t\t\t\t\t// appropriate ranks
\t\t\t\t\trankList[i].push(edge);
\t\t\t\t\tedge.setGeneralPurposeVariable(i, rankList[i]
\t\t\t\t\t\t\t.length - 1);
\t\t\t\t}
\t\t\t}
\t\t}
\t}, rootsArray, false, null);
};

/**
 * Function: visit
 *
 * A depth first search through the internal heirarchy model.
 *
 * Parameters:
 *
 * visitor - The visitor function pattern to be called for each node.
 * trackAncestors - Whether or not the search is to keep track all nodes
 * directly above this one in the search path.
 */
mxSwimlaneModel.prototype.visit = function(visitor, dfsRoots, trackAncestors, seenNodes)
{
\t// Run dfs through on all roots
\tif (dfsRoots != null)
\t{
\t\tfor (var i = 0; i < dfsRoots.length; i++)
\t\t{
\t\t\tvar internalNode = dfsRoots[i];

\t\t\tif (internalNode != null)
\t\t\t{
\t\t\t\tif (seenNodes == null)
\t\t\t\t{
\t\t\t\t\tseenNodes = new Object();
\t\t\t\t}

\t\t\t\tif (trackAncestors)
\t\t\t\t{
\t\t\t\t\t// Set up hash code for root
\t\t\t\t\tinternalNode.hashCode = [];
\t\t\t\t\tinternalNode.hashCode[0] = this.dfsCount;
\t\t\t\t\tinternalNode.hashCode[1] = i;
\t\t\t\t\tthis.extendedDfs(null, internalNode, null, visitor, seenNodes,
\t\t\t\t\t\t\tinternalNode.hashCode, i, 0);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.dfs(null, internalNode, null, visitor, seenNodes, 0);
\t\t\t\t}
\t\t\t}
\t\t}

\t\tthis.dfsCount++;
\t}
};

/**
 * Function: dfs
 *
 * Performs a depth first search on the internal hierarchy model
 *
 * Parameters:
 *
 * parent - the parent internal node of the current internal node
 * root - the current internal node
 * connectingEdge - the internal edge connecting the internal node and the parent
 * internal node, if any
 * visitor - the visitor pattern to be called for each node
 * seen - a set of all nodes seen by this dfs a set of all of the
 * ancestor node of the current node
 * layer - the layer on the dfs tree ( not the same as the model ranks )
 */
mxSwimlaneModel.prototype.dfs = function(parent, root, connectingEdge, visitor, seen, layer)
{
\tif (root != null)
\t{
\t\tvar rootId = root.id;

\t\tif (seen[rootId] == null)
\t\t{
\t\t\tseen[rootId] = root;
\t\t\tvisitor(parent, root, connectingEdge, layer, 0);

\t\t\t// Copy the connects as source list so that visitors
\t\t\t// can change the original for edge direction inversions
\t\t\tvar outgoingEdges = root.connectsAsSource.slice();
\t\t\t
\t\t\tfor (var i = 0; i< outgoingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = outgoingEdges[i];
\t\t\t\tvar targetNode = internalEdge.target;

\t\t\t\t// Root check is O(|roots|)
\t\t\t\tthis.dfs(root, targetNode, internalEdge, visitor, seen,
\t\t\t\t\t\tlayer + 1);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Use the int field to indicate this node has been seen
\t\t\tvisitor(parent, root, connectingEdge, layer, 1);
\t\t}
\t}
};

/**
 * Function: extendedDfs
 *
 * Performs a depth first search on the internal hierarchy model. This dfs
 * extends the default version by keeping track of cells ancestors, but it
 * should be only used when necessary because of it can be computationally
 * intensive for deep searches.
 *
 * Parameters:
 *
 * parent - the parent internal node of the current internal node
 * root - the current internal node
 * connectingEdge - the internal edge connecting the internal node and the parent
 * internal node, if any
 * visitor - the visitor pattern to be called for each node
 * seen - a set of all nodes seen by this dfs
 * ancestors - the parent hash code
 * childHash - the new hash code for this node
 * layer - the layer on the dfs tree ( not the same as the model ranks )
 */
mxSwimlaneModel.prototype.extendedDfs = function(parent, root, connectingEdge, visitor, seen, ancestors, childHash, layer)
{
\t// Explanation of custom hash set. Previously, the ancestors variable
\t// was passed through the dfs as a HashSet. The ancestors were copied
\t// into a new HashSet and when the new child was processed it was also
\t// added to the set. If the current node was in its ancestor list it
\t// meant there is a cycle in the graph and this information is passed
\t// to the visitor.visit() in the seen parameter. The HashSet clone was
\t// very expensive on CPU so a custom hash was developed using primitive
\t// types. temp[] couldn't be used so hashCode[] was added to each node.
\t// Each new child adds another int to the array, copying the prefix
\t// from its parent. Child of the same parent add different ints (the
\t// limit is therefore 2^32 children per parent...). If a node has a
\t// child with the hashCode already set then the child code is compared
\t// to the same portion of the current nodes array. If they match there
\t// is a loop.
\t// Note that the basic mechanism would only allow for 1 use of this
\t// functionality, so the root nodes have two ints. The second int is
\t// incremented through each node root and the first is incremented
\t// through each run of the dfs algorithm (therefore the dfs is not
\t// thread safe). The hash code of each node is set if not already set,
\t// or if the first int does not match that of the current run.
\tif (root != null)
\t{
\t\tif (parent != null)
\t\t{
\t\t\t// Form this nodes hash code if necessary, that is, if the
\t\t\t// hashCode variable has not been initialized or if the
\t\t\t// start of the parent hash code does not equal the start of
\t\t\t// this nodes hash code, indicating the code was set on a
\t\t\t// previous run of this dfs.
\t\t\tif (root.hashCode == null ||
\t\t\t\troot.hashCode[0] != parent.hashCode[0])
\t\t\t{
\t\t\t\tvar hashCodeLength = parent.hashCode.length + 1;
\t\t\t\troot.hashCode = parent.hashCode.slice();
\t\t\t\troot.hashCode[hashCodeLength - 1] = childHash;
\t\t\t}
\t\t}

\t\tvar rootId = root.id;

\t\tif (seen[rootId] == null)
\t\t{
\t\t\tseen[rootId] = root;
\t\t\tvisitor(parent, root, connectingEdge, layer, 0);

\t\t\t// Copy the connects as source list so that visitors
\t\t\t// can change the original for edge direction inversions
\t\t\tvar outgoingEdges = root.connectsAsSource.slice();
\t\t\tvar incomingEdges = root.connectsAsTarget.slice();

\t\t\tfor (var i = 0; i < outgoingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = outgoingEdges[i];
\t\t\t\tvar targetNode = internalEdge.target;
\t\t\t\t
\t\t\t\t// Only navigate in source->target direction within the same
\t\t\t\t// swimlane, or from a lower index swimlane to a higher one
\t\t\t\tif (root.swimlaneIndex <= targetNode.swimlaneIndex)
\t\t\t\t{
\t\t\t\t\tthis.extendedDfs(root, targetNode, internalEdge, visitor, seen,
\t\t\t\t\t\t\troot.hashCode, i, layer + 1);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tfor (var i = 0; i < incomingEdges.length; i++)
\t\t\t{
\t\t\t\tvar internalEdge = incomingEdges[i];
\t\t\t\tvar targetNode = internalEdge.source;

\t\t\t\t// Only navigate in target->source direction from a lower index 
\t\t\t\t// swimlane to a higher one
\t\t\t\tif (root.swimlaneIndex < targetNode.swimlaneIndex)
\t\t\t\t{
\t\t\t\t\tthis.extendedDfs(root, targetNode, internalEdge, visitor, seen,
\t\t\t\t\t\t\troot.hashCode, i, layer + 1);
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Use the int field to indicate this node has been seen
\t\t\tvisitor(parent, root, connectingEdge, layer, 1);
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxHierarchicalLayoutStage
 * 
 * The specific layout interface for hierarchical layouts. It adds a
 * <code>run</code> method with a parameter for the hierarchical layout model
 * that is shared between the layout stages.
 * 
 * Constructor: mxHierarchicalLayoutStage
 *
 * Constructs a new hierarchical layout stage.
 */
function mxHierarchicalLayoutStage() { };

/**
 * Function: execute
 * 
 * Takes the graph detail and configuration information within the facade
 * and creates the resulting laid out graph within that facade for further
 * use.
 */
mxHierarchicalLayoutStage.prototype.execute = function(parent) { };
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxMedianHybridCrossingReduction
 * 
 * Sets the horizontal locations of node and edge dummy nodes on each layer.
 * Uses median down and up weighings as well heuristic to straighten edges as
 * far as possible.
 * 
 * Constructor: mxMedianHybridCrossingReduction
 *
 * Creates a coordinate assignment.
 * 
 * Arguments:
 * 
 * intraCellSpacing - the minimum buffer between cells on the same rank
 * interRankCellSpacing - the minimum distance between cells on adjacent ranks
 * orientation - the position of the root node(s) relative to the graph
 * initialX - the leftmost coordinate node placement starts at
 */
function mxMedianHybridCrossingReduction(layout)
{
\tthis.layout = layout;
};

/**
 * Extends mxMedianHybridCrossingReduction.
 */
mxMedianHybridCrossingReduction.prototype = new mxHierarchicalLayoutStage();
mxMedianHybridCrossingReduction.prototype.constructor = mxMedianHybridCrossingReduction;

/**
 * Variable: layout
 * 
 * Reference to the enclosing <mxHierarchicalLayout>.
 */
mxMedianHybridCrossingReduction.prototype.layout = null;

/**
 * Variable: maxIterations
 * 
 * The maximum number of iterations to perform whilst reducing edge
 * crossings. Default is 24.
 */
mxMedianHybridCrossingReduction.prototype.maxIterations = 24;

/**
 * Variable: nestedBestRanks
 * 
 * Stores each rank as a collection of cells in the best order found for
 * each layer so far
 */
mxMedianHybridCrossingReduction.prototype.nestedBestRanks = null;

/**
 * Variable: currentBestCrossings
 * 
 * The total number of crossings found in the best configuration so far
 */
mxMedianHybridCrossingReduction.prototype.currentBestCrossings = 0;

/**
 * Variable: iterationsWithoutImprovement
 * 
 * The total number of crossings found in the best configuration so far
 */
mxMedianHybridCrossingReduction.prototype.iterationsWithoutImprovement = 0;

/**
 * Variable: maxNoImprovementIterations
 * 
 * The total number of crossings found in the best configuration so far
 */
mxMedianHybridCrossingReduction.prototype.maxNoImprovementIterations = 2;

/**
 * Function: execute
 * 
 * Performs a vertex ordering within ranks as described by Gansner et al
 * 1993
 */
mxMedianHybridCrossingReduction.prototype.execute = function(parent)
{
\tvar model = this.layout.getModel();

\t// Stores initial ordering as being the best one found so far
\tthis.nestedBestRanks = [];
\t
\tfor (var i = 0; i < model.ranks.length; i++)
\t{
\t\tthis.nestedBestRanks[i] = model.ranks[i].slice();
\t}

\tvar iterationsWithoutImprovement = 0;
\tvar currentBestCrossings = this.calculateCrossings(model);

\tfor (var i = 0; i < this.maxIterations &&
\t\titerationsWithoutImprovement < this.maxNoImprovementIterations; i++)
\t{
\t\tthis.weightedMedian(i, model);
\t\tthis.transpose(i, model);
\t\tvar candidateCrossings = this.calculateCrossings(model);

\t\tif (candidateCrossings < currentBestCrossings)
\t\t{
\t\t\tcurrentBestCrossings = candidateCrossings;
\t\t\titerationsWithoutImprovement = 0;

\t\t\t// Store the current rankings as the best ones
\t\t\tfor (var j = 0; j < this.nestedBestRanks.length; j++)
\t\t\t{
\t\t\t\tvar rank = model.ranks[j];

\t\t\t\tfor (var k = 0; k < rank.length; k++)
\t\t\t\t{
\t\t\t\t\tvar cell = rank[k];
\t\t\t\t\tthis.nestedBestRanks[j][cell.getGeneralPurposeVariable(j)] = cell;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Increase count of iterations where we haven't improved the
\t\t\t// layout
\t\t\titerationsWithoutImprovement++;

\t\t\t// Restore the best values to the cells
\t\t\tfor (var j = 0; j < this.nestedBestRanks.length; j++)
\t\t\t{
\t\t\t\tvar rank = model.ranks[j];
\t\t\t\t
\t\t\t\tfor (var k = 0; k < rank.length; k++)
\t\t\t\t{
\t\t\t\t\tvar cell = rank[k];
\t\t\t\t\tcell.setGeneralPurposeVariable(j, k);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (currentBestCrossings == 0)
\t\t{
\t\t\t// Do nothing further
\t\t\tbreak;
\t\t}
\t}

\t// Store the best rankings but in the model
\tvar ranks = [];
\tvar rankList = [];

\tfor (var i = 0; i < model.maxRank + 1; i++)
\t{
\t\trankList[i] = [];
\t\tranks[i] = rankList[i];
\t}

\tfor (var i = 0; i < this.nestedBestRanks.length; i++)
\t{
\t\tfor (var j = 0; j < this.nestedBestRanks[i].length; j++)
\t\t{
\t\t\trankList[i].push(this.nestedBestRanks[i][j]);
\t\t}
\t}

\tmodel.ranks = ranks;
};


/**
 * Function: calculateCrossings
 * 
 * Calculates the total number of edge crossing in the current graph.
 * Returns the current number of edge crossings in the hierarchy graph
 * model in the current candidate layout
 * 
 * Parameters:
 * 
 * model - the internal model describing the hierarchy
 */
mxMedianHybridCrossingReduction.prototype.calculateCrossings = function(model)
{
\tvar numRanks = model.ranks.length;
\tvar totalCrossings = 0;

\tfor (var i = 1; i < numRanks; i++)
\t{
\t\ttotalCrossings += this.calculateRankCrossing(i, model);
\t}
\t
\treturn totalCrossings;
};

/**
 * Function: calculateRankCrossing
 * 
 * Calculates the number of edges crossings between the specified rank and
 * the rank below it. Returns the number of edges crossings with the rank
 * beneath
 * 
 * Parameters:
 * 
 * i -  the topmost rank of the pair ( higher rank value )
 * model - the internal model describing the hierarchy
 */
mxMedianHybridCrossingReduction.prototype.calculateRankCrossing = function(i, model)
{
\tvar totalCrossings = 0;
\tvar rank = model.ranks[i];
\tvar previousRank = model.ranks[i - 1];

\tvar tmpIndices = [];

\t// Iterate over the top rank and fill in the connection information
\tfor (var j = 0; j < rank.length; j++)
\t{
\t\tvar node = rank[j];
\t\tvar rankPosition = node.getGeneralPurposeVariable(i);
\t\tvar connectedCells = node.getPreviousLayerConnectedCells(i);
\t\tvar nodeIndices = [];

\t\tfor (var k = 0; k < connectedCells.length; k++)
\t\t{
\t\t\tvar connectedNode = connectedCells[k];
\t\t\tvar otherCellRankPosition = connectedNode.getGeneralPurposeVariable(i - 1);
\t\t\tnodeIndices.push(otherCellRankPosition);
\t\t}
\t\t
\t\tnodeIndices.sort(function(x, y) { return x - y; });
\t\ttmpIndices[rankPosition] = nodeIndices;
\t}
\t
\tvar indices = [];

\tfor (var j = 0; j < tmpIndices.length; j++)
\t{
\t\tindices = indices.concat(tmpIndices[j]);
\t}

\tvar firstIndex = 1;
\t
\twhile (firstIndex < previousRank.length)
\t{
\t\tfirstIndex <<= 1;
\t}

\tvar treeSize = 2 * firstIndex - 1;
\tfirstIndex -= 1;

\tvar tree = [];
\t
\tfor (var j = 0; j < treeSize; ++j)
\t{
\t\ttree[j] = 0;
\t}

\tfor (var j = 0; j < indices.length; j++)
\t{
\t\tvar index = indices[j];
\t    var treeIndex = index + firstIndex;
\t    ++tree[treeIndex];
\t    
\t    while (treeIndex > 0)
\t    {
\t    \tif (treeIndex % 2)
\t    \t{
\t    \t\ttotalCrossings += tree[treeIndex + 1];
\t    \t}
\t      
\t    \ttreeIndex = (treeIndex - 1) >> 1;
\t    \t++tree[treeIndex];
\t    }
\t}

\treturn totalCrossings;
};

/**
 * Function: transpose
 * 
 * Takes each possible adjacent cell pair on each rank and checks if
 * swapping them around reduces the number of crossing
 * 
 * Parameters:
 * 
 * mainLoopIteration - the iteration number of the main loop
 * model - the internal model describing the hierarchy
 */
mxMedianHybridCrossingReduction.prototype.transpose = function(mainLoopIteration, model)
{
\tvar improved = true;

\t// Track the number of iterations in case of looping
\tvar count = 0;
\tvar maxCount = 10;
\twhile (improved && count++ < maxCount)
\t{
\t\t// On certain iterations allow allow swapping of cell pairs with
\t\t// equal edge crossings switched or not switched. This help to
\t\t// nudge a stuck layout into a lower crossing total.
\t\tvar nudge = mainLoopIteration % 2 == 1 && count % 2 == 1;
\t\timproved = false;
\t\t
\t\tfor (var i = 0; i < model.ranks.length; i++)
\t\t{
\t\t\tvar rank = model.ranks[i];
\t\t\tvar orderedCells = [];
\t\t\t
\t\t\tfor (var j = 0; j < rank.length; j++)
\t\t\t{
\t\t\t\tvar cell = rank[j];
\t\t\t\tvar tempRank = cell.getGeneralPurposeVariable(i);
\t\t\t\t
\t\t\t\t// FIXME: Workaround to avoid negative tempRanks
\t\t\t\tif (tempRank < 0)
\t\t\t\t{
\t\t\t\t\ttempRank = j;
\t\t\t\t}
\t\t\t\torderedCells[tempRank] = cell;
\t\t\t}
\t\t\t
\t\t\tvar leftCellAboveConnections = null;
\t\t\tvar leftCellBelowConnections = null;
\t\t\tvar rightCellAboveConnections = null;
\t\t\tvar rightCellBelowConnections = null;
\t\t\t
\t\t\tvar leftAbovePositions = null;
\t\t\tvar leftBelowPositions = null;
\t\t\tvar rightAbovePositions = null;
\t\t\tvar rightBelowPositions = null;
\t\t\t
\t\t\tvar leftCell = null;
\t\t\tvar rightCell = null;

\t\t\tfor (var j = 0; j < (rank.length - 1); j++)
\t\t\t{
\t\t\t\t// For each intra-rank adjacent pair of cells
\t\t\t\t// see if swapping them around would reduce the
\t\t\t\t// number of edges crossing they cause in total
\t\t\t\t// On every cell pair except the first on each rank, we
\t\t\t\t// can save processing using the previous values for the
\t\t\t\t// right cell on the new left cell
\t\t\t\tif (j == 0)
\t\t\t\t{
\t\t\t\t\tleftCell = orderedCells[j];
\t\t\t\t\tleftCellAboveConnections = leftCell
\t\t\t\t\t\t\t.getNextLayerConnectedCells(i);
\t\t\t\t\tleftCellBelowConnections = leftCell
\t\t\t\t\t\t\t.getPreviousLayerConnectedCells(i);
\t\t\t\t\tleftAbovePositions = [];
\t\t\t\t\tleftBelowPositions = [];
\t\t\t\t\t
\t\t\t\t\tfor (var k = 0; k < leftCellAboveConnections.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tleftAbovePositions[k] = leftCellAboveConnections[k].getGeneralPurposeVariable(i + 1);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tfor (var k = 0; k < leftCellBelowConnections.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tleftBelowPositions[k] = leftCellBelowConnections[k].getGeneralPurposeVariable(i - 1);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tleftCellAboveConnections = rightCellAboveConnections;
\t\t\t\t\tleftCellBelowConnections = rightCellBelowConnections;
\t\t\t\t\tleftAbovePositions = rightAbovePositions;
\t\t\t\t\tleftBelowPositions = rightBelowPositions;
\t\t\t\t\tleftCell = rightCell;
\t\t\t\t}
\t\t\t\t
\t\t\t\trightCell = orderedCells[j + 1];
\t\t\t\trightCellAboveConnections = rightCell
\t\t\t\t\t\t.getNextLayerConnectedCells(i);
\t\t\t\trightCellBelowConnections = rightCell
\t\t\t\t\t\t.getPreviousLayerConnectedCells(i);

\t\t\t\trightAbovePositions = [];
\t\t\t\trightBelowPositions = [];

\t\t\t\tfor (var k = 0; k < rightCellAboveConnections.length; k++)
\t\t\t\t{
\t\t\t\t\trightAbovePositions[k] = rightCellAboveConnections[k].getGeneralPurposeVariable(i + 1);
\t\t\t\t}
\t\t\t\t
\t\t\t\tfor (var k = 0; k < rightCellBelowConnections.length; k++)
\t\t\t\t{
\t\t\t\t\trightBelowPositions[k] = rightCellBelowConnections[k].getGeneralPurposeVariable(i - 1);
\t\t\t\t}

\t\t\t\tvar totalCurrentCrossings = 0;
\t\t\t\tvar totalSwitchedCrossings = 0;
\t\t\t\t
\t\t\t\tfor (var k = 0; k < leftAbovePositions.length; k++)
\t\t\t\t{
\t\t\t\t\tfor (var ik = 0; ik < rightAbovePositions.length; ik++)
\t\t\t\t\t{
\t\t\t\t\t\tif (leftAbovePositions[k] > rightAbovePositions[ik])
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttotalCurrentCrossings++;
\t\t\t\t\t\t}

\t\t\t\t\t\tif (leftAbovePositions[k] < rightAbovePositions[ik])
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttotalSwitchedCrossings++;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tfor (var k = 0; k < leftBelowPositions.length; k++)
\t\t\t\t{
\t\t\t\t\tfor (var ik = 0; ik < rightBelowPositions.length; ik++)
\t\t\t\t\t{
\t\t\t\t\t\tif (leftBelowPositions[k] > rightBelowPositions[ik])
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttotalCurrentCrossings++;
\t\t\t\t\t\t}

\t\t\t\t\t\tif (leftBelowPositions[k] < rightBelowPositions[ik])
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttotalSwitchedCrossings++;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif ((totalSwitchedCrossings < totalCurrentCrossings) ||
\t\t\t\t\t(totalSwitchedCrossings == totalCurrentCrossings &&
\t\t\t\t\tnudge))
\t\t\t\t{
\t\t\t\t\tvar temp = leftCell.getGeneralPurposeVariable(i);
\t\t\t\t\tleftCell.setGeneralPurposeVariable(i, rightCell
\t\t\t\t\t\t\t.getGeneralPurposeVariable(i));
\t\t\t\t\trightCell.setGeneralPurposeVariable(i, temp);

\t\t\t\t\t// With this pair exchanged we have to switch all of
\t\t\t\t\t// values for the left cell to the right cell so the
\t\t\t\t\t// next iteration for this rank uses it as the left
\t\t\t\t\t// cell again
\t\t\t\t\trightCellAboveConnections = leftCellAboveConnections;
\t\t\t\t\trightCellBelowConnections = leftCellBelowConnections;
\t\t\t\t\trightAbovePositions = leftAbovePositions;
\t\t\t\t\trightBelowPositions = leftBelowPositions;
\t\t\t\t\trightCell = leftCell;
\t\t\t\t\t
\t\t\t\t\tif (!nudge)
\t\t\t\t\t{
\t\t\t\t\t\t// Don't count nudges as improvement or we'll end
\t\t\t\t\t\t// up stuck in two combinations and not finishing
\t\t\t\t\t\t// as early as we should
\t\t\t\t\t\timproved = true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: weightedMedian
 * 
 * Sweeps up or down the layout attempting to minimise the median placement
 * of connected cells on adjacent ranks
 * 
 * Parameters:
 * 
 * iteration - the iteration number of the main loop
 * model - the internal model describing the hierarchy
 */
mxMedianHybridCrossingReduction.prototype.weightedMedian = function(iteration, model)
{
\t// Reverse sweep direction each time through this method
\tvar downwardSweep = (iteration % 2 == 0);
\tif (downwardSweep)
\t{
\t\tfor (var j = model.maxRank - 1; j >= 0; j--)
\t\t{
\t\t\tthis.medianRank(j, downwardSweep);
\t\t}
\t}
\telse
\t{
\t\tfor (var j = 1; j < model.maxRank; j++)
\t\t{
\t\t\tthis.medianRank(j, downwardSweep);
\t\t}
\t}
};

/**
 * Function: medianRank
 * 
 * Attempts to minimise the median placement of connected cells on this rank
 * and one of the adjacent ranks
 * 
 * Parameters:
 * 
 * rankValue - the layer number of this rank
 * downwardSweep - whether or not this is a downward sweep through the graph
 */
mxMedianHybridCrossingReduction.prototype.medianRank = function(rankValue, downwardSweep)
{
\tvar numCellsForRank = this.nestedBestRanks[rankValue].length;
\tvar medianValues = [];
\tvar reservedPositions = [];

\tfor (var i = 0; i < numCellsForRank; i++)
\t{
\t\tvar cell = this.nestedBestRanks[rankValue][i];
\t\tvar sorterEntry = new MedianCellSorter();
\t\tsorterEntry.cell = cell;

\t\t// Flip whether or not equal medians are flipped on up and down
\t\t// sweeps
\t\t// TODO re-implement some kind of nudge
\t\t// medianValues[i].nudge = !downwardSweep;
\t\tvar nextLevelConnectedCells;
\t\t
\t\tif (downwardSweep)
\t\t{
\t\t\tnextLevelConnectedCells = cell
\t\t\t\t\t.getNextLayerConnectedCells(rankValue);
\t\t}
\t\telse
\t\t{
\t\t\tnextLevelConnectedCells = cell
\t\t\t\t\t.getPreviousLayerConnectedCells(rankValue);
\t\t}
\t\t
\t\tvar nextRankValue;
\t\t
\t\tif (downwardSweep)
\t\t{
\t\t\tnextRankValue = rankValue + 1;
\t\t}
\t\telse
\t\t{
\t\t\tnextRankValue = rankValue - 1;
\t\t}

\t\tif (nextLevelConnectedCells != null
\t\t\t\t&& nextLevelConnectedCells.length != 0)
\t\t{
\t\t\tsorterEntry.medianValue = this.medianValue(
\t\t\t\t\tnextLevelConnectedCells, nextRankValue);
\t\t\tmedianValues.push(sorterEntry);
\t\t}
\t\telse
\t\t{
\t\t\t// Nodes with no adjacent vertices are flagged in the reserved array
\t\t\t// to indicate they should be left in their current position.
\t\t\treservedPositions[cell.getGeneralPurposeVariable(rankValue)] = true;
\t\t}
\t}
\t
\tmedianValues.sort(MedianCellSorter.prototype.compare);
\t
\t// Set the new position of each node within the rank using
\t// its temp variable
\tfor (var i = 0; i < numCellsForRank; i++)
\t{
\t\tif (reservedPositions[i] == null)
\t\t{
\t\t\tvar cell = medianValues.shift().cell;
\t\t\tcell.setGeneralPurposeVariable(rankValue, i);
\t\t}
\t}
};

/**
 * Function: medianValue
 * 
 * Calculates the median rank order positioning for the specified cell using
 * the connected cells on the specified rank. Returns the median rank
 * ordering value of the connected cells
 * 
 * Parameters:
 * 
 * connectedCells - the cells on the specified rank connected to the
 * specified cell
 * rankValue - the rank that the connected cell lie upon
 */
mxMedianHybridCrossingReduction.prototype.medianValue = function(connectedCells, rankValue)
{
\tvar medianValues = [];
\tvar arrayCount = 0;
\t
\tfor (var i = 0; i < connectedCells.length; i++)
\t{
\t\tvar cell = connectedCells[i];
\t\tmedianValues[arrayCount++] = cell.getGeneralPurposeVariable(rankValue);
\t}

\t// Sort() sorts lexicographically by default (i.e. 11 before 9) so force
\t// numerical order sort
\tmedianValues.sort(function(a,b){return a - b;});
\t
\tif (arrayCount % 2 == 1)
\t{
\t\t// For odd numbers of adjacent vertices return the median
\t\treturn medianValues[Math.floor(arrayCount / 2)];
\t}
\telse if (arrayCount == 2)
\t{
\t\treturn ((medianValues[0] + medianValues[1]) / 2.0);
\t}
\telse
\t{
\t\tvar medianPoint = arrayCount / 2;
\t\tvar leftMedian = medianValues[medianPoint - 1] - medianValues[0];
\t\tvar rightMedian = medianValues[arrayCount - 1]
\t\t\t\t- medianValues[medianPoint];

\t\treturn (medianValues[medianPoint - 1] * rightMedian + medianValues[medianPoint]
\t\t\t\t* leftMedian)
\t\t\t\t/ (leftMedian + rightMedian);
\t}
};

/**
 * Class: MedianCellSorter
 * 
 * A utility class used to track cells whilst sorting occurs on the median
 * values. Does not violate (x.compareTo(y)==0) == (x.equals(y))
 *
 * Constructor: MedianCellSorter
 * 
 * Constructs a new median cell sorter.
 */
function MedianCellSorter()
{
\t// empty
};

/**
 * Variable: medianValue
 * 
 * The weighted value of the cell stored.
 */
MedianCellSorter.prototype.medianValue = 0;

/**
 * Variable: cell
 * 
 * The cell whose median value is being calculated
 */
MedianCellSorter.prototype.cell = false;

/**
 * Function: compare
 * 
 * Compares two MedianCellSorters.
 */
MedianCellSorter.prototype.compare = function(a, b)
{
\tif (a != null && b != null)
\t{
\t\tif (b.medianValue > a.medianValue)
\t\t{
\t\t\treturn -1;
\t\t}
\t\telse if (b.medianValue < a.medianValue)
\t\t{
\t\t\treturn 1;
\t\t}
\t\telse
\t\t{
\t\t\treturn 0;
\t\t}
\t}
\telse
\t{
\t\treturn 0;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxMinimumCycleRemover
 * 
 * An implementation of the first stage of the Sugiyama layout. Straightforward
 * longest path calculation of layer assignment
 * 
 * Constructor: mxMinimumCycleRemover
 *
 * Creates a cycle remover for the given internal model.
 */
function mxMinimumCycleRemover(layout)
{
\tthis.layout = layout;
};

/**
 * Extends mxHierarchicalLayoutStage.
 */
mxMinimumCycleRemover.prototype = new mxHierarchicalLayoutStage();
mxMinimumCycleRemover.prototype.constructor = mxMinimumCycleRemover;

/**
 * Variable: layout
 * 
 * Reference to the enclosing <mxHierarchicalLayout>.
 */
mxMinimumCycleRemover.prototype.layout = null;

/**
 * Function: execute
 * 
 * Takes the graph detail and configuration information within the facade
 * and creates the resulting laid out graph within that facade for further
 * use.
 */
mxMinimumCycleRemover.prototype.execute = function(parent)
{
\tvar model = this.layout.getModel();
\tvar seenNodes = new Object();
\tvar unseenNodesArray = model.vertexMapper.getValues();
\tvar unseenNodes = new Object();
\t
\tfor (var i = 0; i < unseenNodesArray.length; i++)
\t{
\t\tunseenNodes[unseenNodesArray[i].id] = unseenNodesArray[i];
\t}
\t
\t// Perform a dfs through the internal model. If a cycle is found,
\t// reverse it.
\tvar rootsArray = null;
\t
\tif (model.roots != null)
\t{
\t\tvar modelRoots = model.roots;
\t\trootsArray = [];
\t\t
\t\tfor (var i = 0; i < modelRoots.length; i++)
\t\t{
\t\t\trootsArray[i] = model.vertexMapper.get(modelRoots[i]);
\t\t}
\t}

\tmodel.visit(function(parent, node, connectingEdge, layer, seen)
\t{
\t\t// Check if the cell is in it's own ancestor list, if so
\t\t// invert the connecting edge and reverse the target/source
\t\t// relationship to that edge in the parent and the cell
\t\tif (node.isAncestor(parent))
\t\t{
\t\t\tconnectingEdge.invert();
\t\t\tmxUtils.remove(connectingEdge, parent.connectsAsSource);
\t\t\tparent.connectsAsTarget.push(connectingEdge);
\t\t\tmxUtils.remove(connectingEdge, node.connectsAsTarget);
\t\t\tnode.connectsAsSource.push(connectingEdge);
\t\t}
\t\t
\t\tseenNodes[node.id] = node;
\t\tdelete unseenNodes[node.id];
\t}, rootsArray, true, null);

\t// If there are any nodes that should be nodes that the dfs can miss
\t// these need to be processed with the dfs and the roots assigned
\t// correctly to form a correct internal model
\tvar seenNodesCopy = mxUtils.clone(seenNodes, null, true);

\t// Pick a random cell and dfs from it
\tmodel.visit(function(parent, node, connectingEdge, layer, seen)
\t{
\t\t// Check if the cell is in it's own ancestor list, if so
\t\t// invert the connecting edge and reverse the target/source
\t\t// relationship to that edge in the parent and the cell
\t\tif (node.isAncestor(parent))
\t\t{
\t\t\tconnectingEdge.invert();
\t\t\tmxUtils.remove(connectingEdge, parent.connectsAsSource);
\t\t\tnode.connectsAsSource.push(connectingEdge);
\t\t\tparent.connectsAsTarget.push(connectingEdge);
\t\t\tmxUtils.remove(connectingEdge, node.connectsAsTarget);
\t\t}
\t\t
\t\tseenNodes[node.id] = node;
\t\tdelete unseenNodes[node.id];
\t}, unseenNodes, true, seenNodesCopy);
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxCoordinateAssignment
 * 
 * Sets the horizontal locations of node and edge dummy nodes on each layer.
 * Uses median down and up weighings as well as heuristics to straighten edges as
 * far as possible.
 * 
 * Constructor: mxCoordinateAssignment
 *
 * Creates a coordinate assignment.
 * 
 * Arguments:
 * 
 * intraCellSpacing - the minimum buffer between cells on the same rank
 * interRankCellSpacing - the minimum distance between cells on adjacent ranks
 * orientation - the position of the root node(s) relative to the graph
 * initialX - the leftmost coordinate node placement starts at
 */
function mxCoordinateAssignment(layout, intraCellSpacing, interRankCellSpacing,
\torientation, initialX, parallelEdgeSpacing)
{
\tthis.layout = layout;
\tthis.intraCellSpacing = intraCellSpacing;
\tthis.interRankCellSpacing = interRankCellSpacing;
\tthis.orientation = orientation;
\tthis.initialX = initialX;
\tthis.parallelEdgeSpacing = parallelEdgeSpacing;
};

/**
 * Extends mxHierarchicalLayoutStage.
 */
mxCoordinateAssignment.prototype = new mxHierarchicalLayoutStage();
mxCoordinateAssignment.prototype.constructor = mxCoordinateAssignment;

/**
 * Variable: layout
 * 
 * Reference to the enclosing <mxHierarchicalLayout>.
 */
mxCoordinateAssignment.prototype.layout = null;

/**
 * Variable: intraCellSpacing
 * 
 * The minimum buffer between cells on the same rank. Default is 30.
 */
mxCoordinateAssignment.prototype.intraCellSpacing = 30;

/**
 * Variable: interRankCellSpacing
 * 
 * The minimum distance between cells on adjacent ranks. Default is 100.
 */
mxCoordinateAssignment.prototype.interRankCellSpacing = 100;

/**
 * Variable: parallelEdgeSpacing
 * 
 * The distance between each parallel edge on each ranks for long edges.
 * Default is 10.
 */
mxCoordinateAssignment.prototype.parallelEdgeSpacing = 10;

/**
 * Variable: maxIterations
 * 
 * The number of heuristic iterations to run. Default is 8.
 */
mxCoordinateAssignment.prototype.maxIterations = 8;

/**
 * Variable: prefHozEdgeSep
 * 
 * The preferred horizontal distance between edges exiting a vertex Default is 5.
 */
mxCoordinateAssignment.prototype.prefHozEdgeSep = 5;

/**
 * Variable: prefVertEdgeOff
 * 
 * The preferred vertical offset between edges exiting a vertex Default is 2.
 */
mxCoordinateAssignment.prototype.prefVertEdgeOff = 2;

/**
 * Variable: minEdgeJetty
 * 
 * The minimum distance for an edge jetty from a vertex Default is 12.
 */
mxCoordinateAssignment.prototype.minEdgeJetty = 12;

/**
 * Variable: channelBuffer
 * 
 * The size of the vertical buffer in the center of inter-rank channels
 * where edge control points should not be placed Default is 4.
 */
mxCoordinateAssignment.prototype.channelBuffer = 4;

/**
 * Variable: jettyPositions
 * 
 * Map of internal edges and (x,y) pair of positions of the start and end jetty
 * for that edge where it connects to the source and target vertices.
 * Note this should technically be a WeakHashMap, but since JS does not
 * have an equivalent, housekeeping must be performed before using.
 * i.e. check all edges are still in the model and clear the values.
 * Note that the y co-ord is the offset of the jetty, not the
 * absolute point
 */
mxCoordinateAssignment.prototype.jettyPositions = null;

/**
 * Variable: orientation
 * 
 * The position of the root ( start ) node(s) relative to the rest of the
 * laid out graph. Default is <mxConstants.DIRECTION_NORTH>.
 */
mxCoordinateAssignment.prototype.orientation = mxConstants.DIRECTION_NORTH;

/**
 * Variable: initialX
 * 
 * The minimum x position node placement starts at
 */
mxCoordinateAssignment.prototype.initialX = null;

/**
 * Variable: limitX
 * 
 * The maximum x value this positioning lays up to
 */
mxCoordinateAssignment.prototype.limitX = null;

/**
 * Variable: currentXDelta
 * 
 * The sum of x-displacements for the current iteration
 */
mxCoordinateAssignment.prototype.currentXDelta = null;

/**
 * Variable: widestRank
 * 
 * The rank that has the widest x position
 */
mxCoordinateAssignment.prototype.widestRank = null;

/**
 * Variable: rankTopY
 * 
 * Internal cache of top-most values of Y for each rank
 */
mxCoordinateAssignment.prototype.rankTopY = null;

/**
 * Variable: rankBottomY
 * 
 * Internal cache of bottom-most value of Y for each rank
 */
mxCoordinateAssignment.prototype.rankBottomY = null;

/**
 * Variable: widestRankValue
 * 
 * The X-coordinate of the edge of the widest rank
 */
mxCoordinateAssignment.prototype.widestRankValue = null;

/**
 * Variable: rankWidths
 * 
 * The width of all the ranks
 */
mxCoordinateAssignment.prototype.rankWidths = null;

/**
 * Variable: rankY
 * 
 * The Y-coordinate of all the ranks
 */
mxCoordinateAssignment.prototype.rankY = null;

/**
 * Variable: fineTuning
 * 
 * Whether or not to perform local optimisations and iterate multiple times
 * through the algorithm. Default is true.
 */
mxCoordinateAssignment.prototype.fineTuning = true;

/**
 * Variable: nextLayerConnectedCache
 * 
 * A store of connections to the layer above for speed
 */
mxCoordinateAssignment.prototype.nextLayerConnectedCache = null;

/**
 * Variable: previousLayerConnectedCache
 * 
 * A store of connections to the layer below for speed
 */
mxCoordinateAssignment.prototype.previousLayerConnectedCache = null;

/**
 * Variable: groupPadding
 * 
 * Padding added to resized parents Default is 10.
 */
mxCoordinateAssignment.prototype.groupPadding = 10;

/**
 * Utility method to display current positions
 */
mxCoordinateAssignment.prototype.printStatus = function()
{
\tvar model = this.layout.getModel();
\tmxLog.show();

\tmxLog.writeln('======Coord assignment debug=======');

\tfor (var j = 0; j < model.ranks.length; j++)
\t{
\t\tmxLog.write('Rank ', j, ' : ' );
\t\tvar rank = model.ranks[j];
\t\t
\t\tfor (var k = 0; k < rank.length; k++)
\t\t{
\t\t\tvar cell = rank[k];
\t\t\t
\t\t\tmxLog.write(cell.getGeneralPurposeVariable(j), '  ');
\t\t}
\t\tmxLog.writeln();
\t}
\t
\tmxLog.writeln('====================================');
};

/**
 * Function: execute
 * 
 * A basic horizontal coordinate assignment algorithm
 */
mxCoordinateAssignment.prototype.execute = function(parent)
{
\tthis.jettyPositions = Object();
\tvar model = this.layout.getModel();
\tthis.currentXDelta = 0.0;

\tthis.initialCoords(this.layout.getGraph(), model);
\t
//\tthis.printStatus();
\t
\tif (this.fineTuning)
\t{
\t\tthis.minNode(model);
\t}
\t
\tvar bestXDelta = 100000000.0;
\t
\tif (this.fineTuning)
\t{
\t\tfor (var i = 0; i < this.maxIterations; i++)
\t\t{
//\t\t\tthis.printStatus();
\t\t
\t\t\t// Median Heuristic
\t\t\tif (i != 0)
\t\t\t{
\t\t\t\tthis.medianPos(i, model);
\t\t\t\tthis.minNode(model);
\t\t\t}
\t\t\t
\t\t\t// if the total offset is less for the current positioning,
\t\t\t// there are less heavily angled edges and so the current
\t\t\t// positioning is used
\t\t\tif (this.currentXDelta < bestXDelta)
\t\t\t{
\t\t\t\tfor (var j = 0; j < model.ranks.length; j++)
\t\t\t\t{
\t\t\t\t\tvar rank = model.ranks[j];
\t\t\t\t\t
\t\t\t\t\tfor (var k = 0; k < rank.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tvar cell = rank[k];
\t\t\t\t\t\tcell.setX(j, cell.getGeneralPurposeVariable(j));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tbestXDelta = this.currentXDelta;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Restore the best positions
\t\t\t\tfor (var j = 0; j < model.ranks.length; j++)
\t\t\t\t{
\t\t\t\t\tvar rank = model.ranks[j];
\t\t\t\t\t
\t\t\t\t\tfor (var k = 0; k < rank.length; k++)
\t\t\t\t\t{
\t\t\t\t\t\tvar cell = rank[k];
\t\t\t\t\t\tcell.setGeneralPurposeVariable(j, cell.getX(j));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.minPath(this.layout.getGraph(), model);
\t\t\t
\t\t\tthis.currentXDelta = 0;
\t\t}
\t}
\t
\tthis.setCellLocations(this.layout.getGraph(), model);
};

/**
 * Function: minNode
 * 
 * Performs one median positioning sweep in both directions
 */
mxCoordinateAssignment.prototype.minNode = function(model)
{
\t// Queue all nodes
\tvar nodeList = [];
\t
\t// Need to be able to map from cell to cellWrapper
\tvar map = new mxDictionary();
\tvar rank = [];
\t
\tfor (var i = 0; i <= model.maxRank; i++)
\t{
\t\trank[i] = model.ranks[i];
\t\t
\t\tfor (var j = 0; j < rank[i].length; j++)
\t\t{
\t\t\t// Use the weight to store the rank and visited to store whether
\t\t\t// or not the cell is in the list
\t\t\tvar node = rank[i][j];
\t\t\tvar nodeWrapper = new WeightedCellSorter(node, i);
\t\t\tnodeWrapper.rankIndex = j;
\t\t\tnodeWrapper.visited = true;
\t\t\tnodeList.push(nodeWrapper);
\t\t\t
\t\t\tmap.put(node, nodeWrapper);
\t\t}
\t}
\t
\t// Set a limit of the maximum number of times we will access the queue
\t// in case a loop appears
\tvar maxTries = nodeList.length * 10;
\tvar count = 0;
\t
\t// Don't move cell within this value of their median
\tvar tolerance = 1;
\t
\twhile (nodeList.length > 0 && count <= maxTries)
\t{
\t\tvar cellWrapper = nodeList.shift();
\t\tvar cell = cellWrapper.cell;
\t\t
\t\tvar rankValue = cellWrapper.weightedValue;
\t\tvar rankIndex = parseInt(cellWrapper.rankIndex);
\t\t
\t\tvar nextLayerConnectedCells = cell.getNextLayerConnectedCells(rankValue);
\t\tvar previousLayerConnectedCells = cell.getPreviousLayerConnectedCells(rankValue);
\t\t
\t\tvar numNextLayerConnected = nextLayerConnectedCells.length;
\t\tvar numPreviousLayerConnected = previousLayerConnectedCells.length;

\t\tvar medianNextLevel = this.medianXValue(nextLayerConnectedCells,
\t\t\t\trankValue + 1);
\t\tvar medianPreviousLevel = this.medianXValue(previousLayerConnectedCells,
\t\t\t\trankValue - 1);

\t\tvar numConnectedNeighbours = numNextLayerConnected
\t\t\t\t+ numPreviousLayerConnected;
\t\tvar currentPosition = cell.getGeneralPurposeVariable(rankValue);
\t\tvar cellMedian = currentPosition;
\t\t
\t\tif (numConnectedNeighbours > 0)
\t\t{
\t\t\tcellMedian = (medianNextLevel * numNextLayerConnected + medianPreviousLevel
\t\t\t\t\t* numPreviousLayerConnected)
\t\t\t\t\t/ numConnectedNeighbours;
\t\t}

\t\t// Flag storing whether or not position has changed
\t\tvar positionChanged = false;
\t\t
\t\tif (cellMedian < currentPosition - tolerance)
\t\t{
\t\t\tif (rankIndex == 0)
\t\t\t{
\t\t\t\tcell.setGeneralPurposeVariable(rankValue, cellMedian);
\t\t\t\tpositionChanged = true;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar leftCell = rank[rankValue][rankIndex - 1];
\t\t\t\tvar leftLimit = leftCell
\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue);
\t\t\t\tleftLimit = leftLimit + leftCell.width / 2
\t\t\t\t\t\t+ this.intraCellSpacing + cell.width / 2;

\t\t\t\tif (leftLimit < cellMedian)
\t\t\t\t{
\t\t\t\t\tcell.setGeneralPurposeVariable(rankValue, cellMedian);
\t\t\t\t\tpositionChanged = true;
\t\t\t\t}
\t\t\t\telse if (leftLimit < cell
\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue)
\t\t\t\t\t\t- tolerance)
\t\t\t\t{
\t\t\t\t\tcell.setGeneralPurposeVariable(rankValue, leftLimit);
\t\t\t\t\tpositionChanged = true;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (cellMedian > currentPosition + tolerance)
\t\t{
\t\t\tvar rankSize = rank[rankValue].length;
\t\t\t
\t\t\tif (rankIndex == rankSize - 1)
\t\t\t{
\t\t\t\tcell.setGeneralPurposeVariable(rankValue, cellMedian);
\t\t\t\tpositionChanged = true;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar rightCell = rank[rankValue][rankIndex + 1];
\t\t\t\tvar rightLimit = rightCell
\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue);
\t\t\t\trightLimit = rightLimit - rightCell.width / 2
\t\t\t\t\t\t- this.intraCellSpacing - cell.width / 2;
\t\t\t\t
\t\t\t\tif (rightLimit > cellMedian)
\t\t\t\t{
\t\t\t\t\tcell.setGeneralPurposeVariable(rankValue, cellMedian);
\t\t\t\t\tpositionChanged = true;
\t\t\t\t}
\t\t\t\telse if (rightLimit > cell
\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue)
\t\t\t\t\t\t+ tolerance)
\t\t\t\t{
\t\t\t\t\tcell.setGeneralPurposeVariable(rankValue, rightLimit);
\t\t\t\t\tpositionChanged = true;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (positionChanged)
\t\t{
\t\t\t// Add connected nodes to map and list
\t\t\tfor (var i = 0; i < nextLayerConnectedCells.length; i++)
\t\t\t{
\t\t\t\tvar connectedCell = nextLayerConnectedCells[i];
\t\t\t\tvar connectedCellWrapper = map.get(connectedCell);
\t\t\t\t
\t\t\t\tif (connectedCellWrapper != null)
\t\t\t\t{
\t\t\t\t\tif (connectedCellWrapper.visited == false)
\t\t\t\t\t{
\t\t\t\t\t\tconnectedCellWrapper.visited = true;
\t\t\t\t\t\tnodeList.push(connectedCellWrapper);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// Add connected nodes to map and list
\t\t\tfor (var i = 0; i < previousLayerConnectedCells.length; i++)
\t\t\t{
\t\t\t\tvar connectedCell = previousLayerConnectedCells[i];
\t\t\t\tvar connectedCellWrapper = map.get(connectedCell);

\t\t\t\tif (connectedCellWrapper != null)
\t\t\t\t{
\t\t\t\t\tif (connectedCellWrapper.visited == false)
\t\t\t\t\t{
\t\t\t\t\t\tconnectedCellWrapper.visited = true;
\t\t\t\t\t\tnodeList.push(connectedCellWrapper);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tcellWrapper.visited = false;
\t\tcount++;
\t}
};

/**
 * Function: medianPos
 * 
 * Performs one median positioning sweep in one direction
 * 
 * Parameters:
 * 
 * i - the iteration of the whole process
 * model - an internal model of the hierarchical layout
 */
mxCoordinateAssignment.prototype.medianPos = function(i, model)
{
\t// Reverse sweep direction each time through this method
\tvar downwardSweep = (i % 2 == 0);
\t
\tif (downwardSweep)
\t{
\t\tfor (var j = model.maxRank; j > 0; j--)
\t\t{
\t\t\tthis.rankMedianPosition(j - 1, model, j);
\t\t}
\t}
\telse
\t{
\t\tfor (var j = 0; j < model.maxRank - 1; j++)
\t\t{
\t\t\tthis.rankMedianPosition(j + 1, model, j);
\t\t}
\t}
};

/**
 * Function: rankMedianPosition
 * 
 * Performs median minimisation over one rank.
 * 
 * Parameters:
 * 
 * rankValue - the layer number of this rank
 * model - an internal model of the hierarchical layout
 * nextRankValue - the layer number whose connected cels are to be laid out
 * relative to
 */
mxCoordinateAssignment.prototype.rankMedianPosition = function(rankValue, model, nextRankValue)
{
\tvar rank = model.ranks[rankValue];

\t// Form an array of the order in which the cell are to be processed
\t// , the order is given by the weighted sum of the in or out edges,
\t// depending on whether we're traveling up or down the hierarchy.
\tvar weightedValues = [];
\tvar cellMap = new Object();

\tfor (var i = 0; i < rank.length; i++)
\t{
\t\tvar currentCell = rank[i];
\t\tweightedValues[i] = new WeightedCellSorter();
\t\tweightedValues[i].cell = currentCell;
\t\tweightedValues[i].rankIndex = i;
\t\tcellMap[currentCell.id] = weightedValues[i];
\t\tvar nextLayerConnectedCells = null;
\t\t
\t\tif (nextRankValue < rankValue)
\t\t{
\t\t\tnextLayerConnectedCells = currentCell
\t\t\t\t\t.getPreviousLayerConnectedCells(rankValue);
\t\t}
\t\telse
\t\t{
\t\t\tnextLayerConnectedCells = currentCell
\t\t\t\t\t.getNextLayerConnectedCells(rankValue);
\t\t}

\t\t// Calculate the weighing based on this node type and those this
\t\t// node is connected to on the next layer
\t\tweightedValues[i].weightedValue = this.calculatedWeightedValue(
\t\t\t\tcurrentCell, nextLayerConnectedCells);
\t}

\tweightedValues.sort(WeightedCellSorter.prototype.compare);

\t// Set the new position of each node within the rank using
\t// its temp variable
\t
\tfor (var i = 0; i < weightedValues.length; i++)
\t{
\t\tvar numConnectionsNextLevel = 0;
\t\tvar cell = weightedValues[i].cell;
\t\tvar nextLayerConnectedCells = null;
\t\tvar medianNextLevel = 0;

\t\tif (nextRankValue < rankValue)
\t\t{
\t\t\tnextLayerConnectedCells = cell.getPreviousLayerConnectedCells(
\t\t\t\t\trankValue).slice();
\t\t}
\t\telse
\t\t{
\t\t\tnextLayerConnectedCells = cell.getNextLayerConnectedCells(
\t\t\t\t\trankValue).slice();
\t\t}

\t\tif (nextLayerConnectedCells != null)
\t\t{
\t\t\tnumConnectionsNextLevel = nextLayerConnectedCells.length;
\t\t\t
\t\t\tif (numConnectionsNextLevel > 0)
\t\t\t{
\t\t\t\tmedianNextLevel = this.medianXValue(nextLayerConnectedCells,
\t\t\t\t\t\tnextRankValue);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// For case of no connections on the next level set the
\t\t\t\t// median to be the current position and try to be
\t\t\t\t// positioned there
\t\t\t\tmedianNextLevel = cell.getGeneralPurposeVariable(rankValue);
\t\t\t}
\t\t}

\t\tvar leftBuffer = 0.0;
\t\tvar leftLimit = -100000000.0;
\t\t
\t\tfor (var j = weightedValues[i].rankIndex - 1; j >= 0;)
\t\t{
\t\t\tvar weightedValue = cellMap[rank[j].id];
\t\t\t
\t\t\tif (weightedValue != null)
\t\t\t{
\t\t\t\tvar leftCell = weightedValue.cell;
\t\t\t\t
\t\t\t\tif (weightedValue.visited)
\t\t\t\t{
\t\t\t\t\t// The left limit is the right hand limit of that
\t\t\t\t\t// cell plus any allowance for unallocated cells
\t\t\t\t\t// in-between
\t\t\t\t\tleftLimit = leftCell
\t\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue)
\t\t\t\t\t\t\t+ leftCell.width
\t\t\t\t\t\t\t/ 2.0
\t\t\t\t\t\t\t+ this.intraCellSpacing
\t\t\t\t\t\t\t+ leftBuffer + cell.width / 2.0;
\t\t\t\t\tj = -1;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tleftBuffer += leftCell.width + this.intraCellSpacing;
\t\t\t\t\tj--;
\t\t\t\t}
\t\t\t}
\t\t}

\t\tvar rightBuffer = 0.0;
\t\tvar rightLimit = 100000000.0;
\t\t
\t\tfor (var j = weightedValues[i].rankIndex + 1; j < weightedValues.length;)
\t\t{
\t\t\tvar weightedValue = cellMap[rank[j].id];
\t\t\t
\t\t\tif (weightedValue != null)
\t\t\t{
\t\t\t\tvar rightCell = weightedValue.cell;
\t\t\t\t
\t\t\t\tif (weightedValue.visited)
\t\t\t\t{
\t\t\t\t\t// The left limit is the right hand limit of that
\t\t\t\t\t// cell plus any allowance for unallocated cells
\t\t\t\t\t// in-between
\t\t\t\t\trightLimit = rightCell
\t\t\t\t\t\t\t.getGeneralPurposeVariable(rankValue)
\t\t\t\t\t\t\t- rightCell.width
\t\t\t\t\t\t\t/ 2.0
\t\t\t\t\t\t\t- this.intraCellSpacing
\t\t\t\t\t\t\t- rightBuffer - cell.width / 2.0;
\t\t\t\t\tj = weightedValues.length;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\trightBuffer += rightCell.width + this.intraCellSpacing;
\t\t\t\t\tj++;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (medianNextLevel >= leftLimit && medianNextLevel <= rightLimit)
\t\t{
\t\t\tcell.setGeneralPurposeVariable(rankValue, medianNextLevel);
\t\t}
\t\telse if (medianNextLevel < leftLimit)
\t\t{
\t\t\t// Couldn't place at median value, place as close to that
\t\t\t// value as possible
\t\t\tcell.setGeneralPurposeVariable(rankValue, leftLimit);
\t\t\tthis.currentXDelta += leftLimit - medianNextLevel;
\t\t}
\t\telse if (medianNextLevel > rightLimit)
\t\t{
\t\t\t// Couldn't place at median value, place as close to that
\t\t\t// value as possible
\t\t\tcell.setGeneralPurposeVariable(rankValue, rightLimit);
\t\t\tthis.currentXDelta += medianNextLevel - rightLimit;
\t\t}

\t\tweightedValues[i].visited = true;
\t}
};

/**
 * Function: calculatedWeightedValue
 * 
 * Calculates the priority the specified cell has based on the type of its
 * cell and the cells it is connected to on the next layer
 * 
 * Parameters:
 * 
 * currentCell - the cell whose weight is to be calculated
 * collection - the cells the specified cell is connected to
 */
mxCoordinateAssignment.prototype.calculatedWeightedValue = function(currentCell, collection)
{
\tvar totalWeight = 0;
\t
\tfor (var i = 0; i < collection.length; i++)
\t{
\t\tvar cell = collection[i];

\t\tif (currentCell.isVertex() && cell.isVertex())
\t\t{
\t\t\ttotalWeight++;
\t\t}
\t\telse if (currentCell.isEdge() && cell.isEdge())
\t\t{
\t\t\ttotalWeight += 8;
\t\t}
\t\telse
\t\t{
\t\t\ttotalWeight += 2;
\t\t}
\t}

\treturn totalWeight;
};

/**
 * Function: medianXValue
 * 
 * Calculates the median position of the connected cell on the specified
 * rank
 * 
 * Parameters:
 * 
 * connectedCells - the cells the candidate connects to on this level
 * rankValue - the layer number of this rank
 */
mxCoordinateAssignment.prototype.medianXValue = function(connectedCells, rankValue)
{
\tif (connectedCells.length == 0)
\t{
\t\treturn 0;
\t}

\tvar medianValues = [];

\tfor (var i = 0; i < connectedCells.length; i++)
\t{
\t\tmedianValues[i] = connectedCells[i].getGeneralPurposeVariable(rankValue);
\t}

\tmedianValues.sort(function(a,b){return a - b;});
\t
\tif (connectedCells.length % 2 == 1)
\t{
\t\t// For odd numbers of adjacent vertices return the median
\t\treturn medianValues[Math.floor(connectedCells.length / 2)];
\t}
\telse
\t{
\t\tvar medianPoint = connectedCells.length / 2;
\t\tvar leftMedian = medianValues[medianPoint - 1];
\t\tvar rightMedian = medianValues[medianPoint];

\t\treturn ((leftMedian + rightMedian) / 2);
\t}
};

/**
 * Function: initialCoords
 * 
 * Sets up the layout in an initial positioning. The ranks are all centered
 * as much as possible along the middle vertex in each rank. The other cells
 * are then placed as close as possible on either side.
 * 
 * Parameters:
 * 
 * facade - the facade describing the input graph
 * model - an internal model of the hierarchical layout
 */
mxCoordinateAssignment.prototype.initialCoords = function(facade, model)
{
\tthis.calculateWidestRank(facade, model);

\t// Sweep up and down from the widest rank
\tfor (var i = this.widestRank; i >= 0; i--)
\t{
\t\tif (i < model.maxRank)
\t\t{
\t\t\tthis.rankCoordinates(i, facade, model);
\t\t}
\t}

\tfor (var i = this.widestRank+1; i <= model.maxRank; i++)
\t{
\t\tif (i > 0)
\t\t{
\t\t\tthis.rankCoordinates(i, facade, model);
\t\t}
\t}
};

/**
 * Function: rankCoordinates
 * 
 * Sets up the layout in an initial positioning. All the first cells in each
 * rank are moved to the left and the rest of the rank inserted as close
 * together as their size and buffering permits. This method works on just
 * the specified rank.
 * 
 * Parameters:
 * 
 * rankValue - the current rank being processed
 * graph - the facade describing the input graph
 * model - an internal model of the hierarchical layout
 */
mxCoordinateAssignment.prototype.rankCoordinates = function(rankValue, graph, model)
{
\tvar rank = model.ranks[rankValue];
\tvar maxY = 0.0;
\tvar localX = this.initialX + (this.widestRankValue - this.rankWidths[rankValue])
\t\t\t/ 2;

\t// Store whether or not any of the cells' bounds were unavailable so
\t// to only issue the warning once for all cells
\tvar boundsWarning = false;
\t
\tfor (var i = 0; i < rank.length; i++)
\t{
\t\tvar node = rank[i];
\t\t
\t\tif (node.isVertex())
\t\t{
\t\t\tvar bounds = this.layout.getVertexBounds(node.cell);

\t\t\tif (bounds != null)
\t\t\t{
\t\t\t\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\t\t\t\tthis.orientation == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tnode.width = bounds.width;
\t\t\t\t\tnode.height = bounds.height;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tnode.width = bounds.height;
\t\t\t\t\tnode.height = bounds.width;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tboundsWarning = true;
\t\t\t}

\t\t\tmaxY = Math.max(maxY, node.height);
\t\t}
\t\telse if (node.isEdge())
\t\t{
\t\t\t// The width is the number of additional parallel edges
\t\t\t// time the parallel edge spacing
\t\t\tvar numEdges = 1;

\t\t\tif (node.edges != null)
\t\t\t{
\t\t\t\tnumEdges = node.edges.length;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tmxLog.warn('edge.edges is null');
\t\t\t}

\t\t\tnode.width = (numEdges - 1) * this.parallelEdgeSpacing;
\t\t}

\t\t// Set the initial x-value as being the best result so far
\t\tlocalX += node.width / 2.0;
\t\tnode.setX(rankValue, localX);
\t\tnode.setGeneralPurposeVariable(rankValue, localX);
\t\tlocalX += node.width / 2.0;
\t\tlocalX += this.intraCellSpacing;
\t}

\tif (boundsWarning == true)
\t{
\t\tmxLog.warn('At least one cell has no bounds');
\t}
};

/**
 * Function: calculateWidestRank
 * 
 * Calculates the width rank in the hierarchy. Also set the y value of each
 * rank whilst performing the calculation
 * 
 * Parameters:
 * 
 * graph - the facade describing the input graph
 * model - an internal model of the hierarchical layout
 */
mxCoordinateAssignment.prototype.calculateWidestRank = function(graph, model)
{
\t// Starting y co-ordinate
\tvar y = -this.interRankCellSpacing;
\t
\t// Track the widest cell on the last rank since the y
\t// difference depends on it
\tvar lastRankMaxCellHeight = 0.0;
\tthis.rankWidths = [];
\tthis.rankY = [];

\tfor (var rankValue = model.maxRank; rankValue >= 0; rankValue--)
\t{
\t\t// Keep track of the widest cell on this rank
\t\tvar maxCellHeight = 0.0;
\t\tvar rank = model.ranks[rankValue];
\t\tvar localX = this.initialX;

\t\t// Store whether or not any of the cells' bounds were unavailable so
\t\t// to only issue the warning once for all cells
\t\tvar boundsWarning = false;
\t\t
\t\tfor (var i = 0; i < rank.length; i++)
\t\t{
\t\t\tvar node = rank[i];

\t\t\tif (node.isVertex())
\t\t\t{
\t\t\t\tvar bounds = this.layout.getVertexBounds(node.cell);

\t\t\t\tif (bounds != null)
\t\t\t\t{
\t\t\t\t\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\t\t\t\t\tthis.orientation == mxConstants.DIRECTION_SOUTH)
\t\t\t\t\t{
\t\t\t\t\t\tnode.width = bounds.width;
\t\t\t\t\t\tnode.height = bounds.height;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tnode.width = bounds.height;
\t\t\t\t\t\tnode.height = bounds.width;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tboundsWarning = true;
\t\t\t\t}

\t\t\t\tmaxCellHeight = Math.max(maxCellHeight, node.height);
\t\t\t}
\t\t\telse if (node.isEdge())
\t\t\t{
\t\t\t\t// The width is the number of additional parallel edges
\t\t\t\t// time the parallel edge spacing
\t\t\t\tvar numEdges = 1;

\t\t\t\tif (node.edges != null)
\t\t\t\t{
\t\t\t\t\tnumEdges = node.edges.length;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tmxLog.warn('edge.edges is null');
\t\t\t\t}

\t\t\t\tnode.width = (numEdges - 1) * this.parallelEdgeSpacing;
\t\t\t}

\t\t\t// Set the initial x-value as being the best result so far
\t\t\tlocalX += node.width / 2.0;
\t\t\tnode.setX(rankValue, localX);
\t\t\tnode.setGeneralPurposeVariable(rankValue, localX);
\t\t\tlocalX += node.width / 2.0;
\t\t\tlocalX += this.intraCellSpacing;

\t\t\tif (localX > this.widestRankValue)
\t\t\t{
\t\t\t\tthis.widestRankValue = localX;
\t\t\t\tthis.widestRank = rankValue;
\t\t\t}

\t\t\tthis.rankWidths[rankValue] = localX;
\t\t}

\t\tif (boundsWarning == true)
\t\t{
\t\t\tmxLog.warn('At least one cell has no bounds');
\t\t}

\t\tthis.rankY[rankValue] = y;
\t\tvar distanceToNextRank = maxCellHeight / 2.0
\t\t\t\t+ lastRankMaxCellHeight / 2.0 + this.interRankCellSpacing;
\t\tlastRankMaxCellHeight = maxCellHeight;

\t\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\t\tthis.orientation == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\ty += distanceToNextRank;
\t\t}
\t\telse
\t\t{
\t\t\ty -= distanceToNextRank;
\t\t}

\t\tfor (var i = 0; i < rank.length; i++)
\t\t{
\t\t\tvar cell = rank[i];
\t\t\tcell.setY(rankValue, y);
\t\t}
\t}
};

/**
 * Function: minPath
 * 
 * Straightens out chains of virtual nodes where possibleacade to those stored after this layout
 * processing step has completed.
 * 
 * Parameters:
 *
 * graph - the facade describing the input graph
 * model - an internal model of the hierarchical layout
 */
mxCoordinateAssignment.prototype.minPath = function(graph, model)
{
\t// Work down and up each edge with at least 2 control points
\t// trying to straighten each one out. If the same number of
\t// straight segments are formed in both directions, the 
\t// preferred direction used is the one where the final
\t// control points have the least offset from the connectable 
\t// region of the terminating vertices
\tvar edges = model.edgeMapper.getValues();
\t
\tfor (var j = 0; j < edges.length; j++)
\t{
\t\tvar cell = edges[j];
\t\t
\t\tif (cell.maxRank - cell.minRank - 1 < 1)
\t\t{
\t\t\tcontinue;
\t\t}

\t\t// At least two virtual nodes in the edge
\t\t// Check first whether the edge is already straight
\t\tvar referenceX = cell
\t\t\t\t.getGeneralPurposeVariable(cell.minRank + 1);
\t\tvar edgeStraight = true;
\t\tvar refSegCount = 0;
\t\t
\t\tfor (var i = cell.minRank + 2; i < cell.maxRank; i++)
\t\t{
\t\t\tvar x = cell.getGeneralPurposeVariable(i);

\t\t\tif (referenceX != x)
\t\t\t{
\t\t\t\tedgeStraight = false;
\t\t\t\treferenceX = x;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\trefSegCount++;
\t\t\t}
\t\t}

\t\tif (!edgeStraight)
\t\t{
\t\t\tvar upSegCount = 0;
\t\t\tvar downSegCount = 0;
\t\t\tvar upXPositions = [];
\t\t\tvar downXPositions = [];

\t\t\tvar currentX = cell.getGeneralPurposeVariable(cell.minRank + 1);

\t\t\tfor (var i = cell.minRank + 1; i < cell.maxRank - 1; i++)
\t\t\t{
\t\t\t\t// Attempt to straight out the control point on the
\t\t\t\t// next segment up with the current control point.
\t\t\t\tvar nextX = cell.getX(i + 1);

\t\t\t\tif (currentX == nextX)
\t\t\t\t{
\t\t\t\t\tupXPositions[i - cell.minRank - 1] = currentX;
\t\t\t\t\tupSegCount++;
\t\t\t\t}
\t\t\t\telse if (this.repositionValid(model, cell, i + 1, currentX))
\t\t\t\t{
\t\t\t\t\tupXPositions[i - cell.minRank - 1] = currentX;
\t\t\t\t\tupSegCount++;
\t\t\t\t\t// Leave currentX at same value
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tupXPositions[i - cell.minRank - 1] = nextX;
\t\t\t\t\tcurrentX = nextX;
\t\t\t\t}\t\t\t\t
\t\t\t}

\t\t\tcurrentX = cell.getX(i);

\t\t\tfor (var i = cell.maxRank - 1; i > cell.minRank + 1; i--)
\t\t\t{
\t\t\t\t// Attempt to straight out the control point on the
\t\t\t\t// next segment down with the current control point.
\t\t\t\tvar nextX = cell.getX(i - 1);

\t\t\t\tif (currentX == nextX)
\t\t\t\t{
\t\t\t\t\tdownXPositions[i - cell.minRank - 2] = currentX;
\t\t\t\t\tdownSegCount++;
\t\t\t\t}
\t\t\t\telse if (this.repositionValid(model, cell, i - 1, currentX))
\t\t\t\t{
\t\t\t\t\tdownXPositions[i - cell.minRank - 2] = currentX;
\t\t\t\t\tdownSegCount++;
\t\t\t\t\t// Leave currentX at same value
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tdownXPositions[i - cell.minRank - 2] = cell.getX(i-1);
\t\t\t\t\tcurrentX = nextX;
\t\t\t\t}
\t\t\t}

\t\t\tif (downSegCount > refSegCount || upSegCount > refSegCount)
\t\t\t{
\t\t\t\tif (downSegCount >= upSegCount)
\t\t\t\t{
\t\t\t\t\t// Apply down calculation values
\t\t\t\t\tfor (var i = cell.maxRank - 2; i > cell.minRank; i--)
\t\t\t\t\t{
\t\t\t\t\t\tcell.setX(i, downXPositions[i - cell.minRank - 1]);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (upSegCount > downSegCount)
\t\t\t\t{
\t\t\t\t\t// Apply up calculation values
\t\t\t\t\tfor (var i = cell.minRank + 2; i < cell.maxRank; i++)
\t\t\t\t\t{
\t\t\t\t\t\tcell.setX(i, upXPositions[i - cell.minRank - 2]);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\t// Neither direction provided a favourable result
\t\t\t\t\t// But both calculations are better than the
\t\t\t\t\t// existing solution, so apply the one with minimal
\t\t\t\t\t// offset to attached vertices at either end.
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: repositionValid
 * 
 * Determines whether or not a node may be moved to the specified x 
 * position on the specified rank
 * 
 * Parameters:
 *
 * model - the layout model
 * cell - the cell being analysed
 * rank - the layer of the cell
 * position - the x position being sought
 */
mxCoordinateAssignment.prototype.repositionValid = function(model, cell, rank, position)
{
\tvar rankArray = model.ranks[rank];
\tvar rankIndex = -1;

\tfor (var i = 0; i < rankArray.length; i++)
\t{
\t\tif (cell == rankArray[i])
\t\t{
\t\t\trankIndex = i;
\t\t\tbreak;
\t\t}
\t}

\tif (rankIndex < 0)
\t{
\t\treturn false;
\t}

\tvar currentX = cell.getGeneralPurposeVariable(rank);

\tif (position < currentX)
\t{
\t\t// Trying to move node to the left.
\t\tif (rankIndex == 0)
\t\t{
\t\t\t// Left-most node, can move anywhere
\t\t\treturn true;
\t\t}

\t\tvar leftCell = rankArray[rankIndex - 1];
\t\tvar leftLimit = leftCell.getGeneralPurposeVariable(rank);
\t\tleftLimit = leftLimit + leftCell.width / 2
\t\t\t\t+ this.intraCellSpacing + cell.width / 2;

\t\tif (leftLimit <= position)
\t\t{
\t\t\treturn true;
\t\t}
\t\telse
\t\t{
\t\t\treturn false;
\t\t}
\t}
\telse if (position > currentX)
\t{
\t\t// Trying to move node to the right.
\t\tif (rankIndex == rankArray.length - 1)
\t\t{
\t\t\t// Right-most node, can move anywhere
\t\t\treturn true;
\t\t}

\t\tvar rightCell = rankArray[rankIndex + 1];
\t\tvar rightLimit = rightCell.getGeneralPurposeVariable(rank);
\t\trightLimit = rightLimit - rightCell.width / 2
\t\t\t\t- this.intraCellSpacing - cell.width / 2;

\t\tif (rightLimit >= position)
\t\t{
\t\t\treturn true;
\t\t}
\t\telse
\t\t{
\t\t\treturn false;
\t\t}
\t}

\treturn true;
};

/**
 * Function: setCellLocations
 * 
 * Sets the cell locations in the facade to those stored after this layout
 * processing step has completed.
 * 
 * Parameters:
 *
 * graph - the input graph
 * model - the layout model
 */
mxCoordinateAssignment.prototype.setCellLocations = function(graph, model)
{
\tthis.rankTopY = [];
\tthis.rankBottomY = [];

\tfor (var i = 0; i < model.ranks.length; i++)
\t{
\t\tthis.rankTopY[i] = Number.MAX_VALUE;
\t\tthis.rankBottomY[i] = -Number.MAX_VALUE;
\t}
\t
\tvar vertices = model.vertexMapper.getValues();

\t// Process vertices all first, since they define the lower and 
\t// limits of each rank. Between these limits lie the channels
\t// where the edges can be routed across the graph

\tfor (var i = 0; i < vertices.length; i++)
\t{
\t\tthis.setVertexLocation(vertices[i]);
\t}
\t
\t// Post process edge styles. Needs the vertex locations set for initial
\t// values of the top and bottoms of each rank
\tif (this.layout.edgeStyle == mxHierarchicalEdgeStyle.ORTHOGONAL
\t\t\t|| this.layout.edgeStyle == mxHierarchicalEdgeStyle.POLYLINE
\t\t\t|| this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
\t{
\t\tthis.localEdgeProcessing(model);
\t}

\tvar edges = model.edgeMapper.getValues();

\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tthis.setEdgePosition(edges[i]);
\t}
};

/**
 * Function: localEdgeProcessing
 * 
 * Separates the x position of edges as they connect to vertices
 * 
 * Parameters:
 *
 * model - the layout model
 */
mxCoordinateAssignment.prototype.localEdgeProcessing = function(model)
{
\t// Iterate through each vertex, look at the edges connected in
\t// both directions.
\tfor (var rankIndex = 0; rankIndex < model.ranks.length; rankIndex++)
\t{
\t\tvar rank = model.ranks[rankIndex];

\t\tfor (var cellIndex = 0; cellIndex < rank.length; cellIndex++)
\t\t{
\t\t\tvar cell = rank[cellIndex];

\t\t\tif (cell.isVertex())
\t\t\t{
\t\t\t\tvar currentCells = cell.getPreviousLayerConnectedCells(rankIndex);

\t\t\t\tvar currentRank = rankIndex - 1;

\t\t\t\t// Two loops, last connected cells, and next
\t\t\t\tfor (var k = 0; k < 2; k++)
\t\t\t\t{
\t\t\t\t\tif (currentRank > -1
\t\t\t\t\t\t\t&& currentRank < model.ranks.length
\t\t\t\t\t\t\t&& currentCells != null
\t\t\t\t\t\t\t&& currentCells.length > 0)
\t\t\t\t\t{
\t\t\t\t\t\tvar sortedCells = [];

\t\t\t\t\t\tfor (var j = 0; j < currentCells.length; j++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar sorter = new WeightedCellSorter(
\t\t\t\t\t\t\t\t\tcurrentCells[j], currentCells[j].getX(currentRank));
\t\t\t\t\t\t\tsortedCells.push(sorter);
\t\t\t\t\t\t}

\t\t\t\t\t\tsortedCells.sort(WeightedCellSorter.prototype.compare);

\t\t\t\t\t\tvar leftLimit = cell.x[0] - cell.width / 2;
\t\t\t\t\t\tvar rightLimit = leftLimit + cell.width;

\t\t\t\t\t\t// Connected edge count starts at 1 to allow for buffer
\t\t\t\t\t\t// with edge of vertex
\t\t\t\t\t\tvar connectedEdgeCount = 0;
\t\t\t\t\t\tvar connectedEdgeGroupCount = 0;
\t\t\t\t\t\tvar connectedEdges = [];
\t\t\t\t\t\t// Calculate width requirements for all connected edges
\t\t\t\t\t\tfor (var j = 0; j < sortedCells.length; j++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar innerCell = sortedCells[j].cell;
\t\t\t\t\t\t\tvar connections;

\t\t\t\t\t\t\tif (innerCell.isVertex())
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t// Get the connecting edge
\t\t\t\t\t\t\t\tif (k == 0)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tconnections = cell.connectsAsSource;

\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tconnections = cell.connectsAsTarget;
\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\tfor (var connIndex = 0; connIndex < connections.length; connIndex++)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tif (connections[connIndex].source == innerCell
\t\t\t\t\t\t\t\t\t\t\t|| connections[connIndex].target == innerCell)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tconnectedEdgeCount += connections[connIndex].edges
\t\t\t\t\t\t\t\t\t\t\t\t.length;
\t\t\t\t\t\t\t\t\t\tconnectedEdgeGroupCount++;

\t\t\t\t\t\t\t\t\t\tconnectedEdges.push(connections[connIndex]);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tconnectedEdgeCount += innerCell.edges.length;
\t\t\t\t\t\t\t\tconnectedEdgeGroupCount++;
\t\t\t\t\t\t\t\tconnectedEdges.push(innerCell);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}

\t\t\t\t\t\tvar requiredWidth = (connectedEdgeCount + 1)
\t\t\t\t\t\t\t\t* this.prefHozEdgeSep;

\t\t\t\t\t\t// Add a buffer on the edges of the vertex if the edge count allows
\t\t\t\t\t\tif (cell.width > requiredWidth
\t\t\t\t\t\t\t\t+ (2 * this.prefHozEdgeSep))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tleftLimit += this.prefHozEdgeSep;
\t\t\t\t\t\t\trightLimit -= this.prefHozEdgeSep;
\t\t\t\t\t\t}

\t\t\t\t\t\tvar availableWidth = rightLimit - leftLimit;
\t\t\t\t\t\tvar edgeSpacing = availableWidth / connectedEdgeCount;

\t\t\t\t\t\tvar currentX = leftLimit + edgeSpacing / 2.0;
\t\t\t\t\t\tvar currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff;
\t\t\t\t\t\tvar maxYOffset = 0;

\t\t\t\t\t\tfor (var j = 0; j < connectedEdges.length; j++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar numActualEdges = connectedEdges[j].edges
\t\t\t\t\t\t\t\t\t.length;
\t\t\t\t\t\t\tvar pos = this.jettyPositions[connectedEdges[j].ids[0]];
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (pos == null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tpos = [];
\t\t\t\t\t\t\t\tthis.jettyPositions[connectedEdges[j].ids[0]] = pos;
\t\t\t\t\t\t\t}

\t\t\t\t\t\t\tif (j < connectedEdgeCount / 2)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tcurrentYOffset += this.prefVertEdgeOff;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (j > connectedEdgeCount / 2)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tcurrentYOffset -= this.prefVertEdgeOff;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t// Ignore the case if equals, this means the second of 2
\t\t\t\t\t\t\t// jettys with the same y (even number of edges)

\t\t\t\t\t\t\tfor (var m = 0; m < numActualEdges; m++)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tpos[m * 4 + k * 2] = currentX;
\t\t\t\t\t\t\t\tcurrentX += edgeSpacing;
\t\t\t\t\t\t\t\tpos[m * 4 + k * 2 + 1] = currentYOffset;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tmaxYOffset = Math.max(maxYOffset,
\t\t\t\t\t\t\t\t\tcurrentYOffset);
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\tcurrentCells = cell.getNextLayerConnectedCells(rankIndex);

\t\t\t\t\tcurrentRank = rankIndex + 1;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: setEdgePosition
 * 
 * Fixes the control points
 */
mxCoordinateAssignment.prototype.setEdgePosition = function(cell)
{
\t// For parallel edges we need to seperate out the points a
\t// little
\tvar offsetX = 0;
\t// Only set the edge control points once

\tif (cell.temp[0] != 101207)
\t{
\t\tvar maxRank = cell.maxRank;
\t\tvar minRank = cell.minRank;
\t\t
\t\tif (maxRank == minRank)
\t\t{
\t\t\tmaxRank = cell.source.maxRank;
\t\t\tminRank = cell.target.minRank;
\t\t}
\t\t
\t\tvar parallelEdgeCount = 0;
\t\tvar jettys = this.jettyPositions[cell.ids[0]];

\t\tvar source = cell.isReversed ? cell.target.cell : cell.source.cell;
\t\tvar graph = this.layout.graph;
\t\tvar layoutReversed = this.orientation == mxConstants.DIRECTION_EAST
\t\t\t\t|| this.orientation == mxConstants.DIRECTION_SOUTH;

\t\tfor (var i = 0; i < cell.edges.length; i++)
\t\t{
\t\t\tvar realEdge = cell.edges[i];
\t\t\tvar realSource = this.layout.getVisibleTerminal(realEdge, true);

\t\t\t//List oldPoints = graph.getPoints(realEdge);
\t\t\tvar newPoints = [];

\t\t\t// Single length reversed edges end up with the jettys in the wrong
\t\t\t// places. Since single length edges only have jettys, not segment
\t\t\t// control points, we just say the edge isn't reversed in this section
\t\t\tvar reversed = cell.isReversed;
\t\t\t
\t\t\tif (realSource != source)
\t\t\t{
\t\t\t\t// The real edges include all core model edges and these can go
\t\t\t\t// in both directions. If the source of the hierarchical model edge
\t\t\t\t// isn't the source of the specific real edge in this iteration
\t\t\t\t// treat if as reversed
\t\t\t\treversed = !reversed;
\t\t\t}

\t\t\t// First jetty of edge
\t\t\tif (jettys != null)
\t\t\t{
\t\t\t\tvar arrayOffset = reversed ? 2 : 0;
\t\t\t\tvar y = reversed ?
\t\t\t\t\t\t(layoutReversed ? this.rankBottomY[minRank] : this.rankTopY[minRank]) :
\t\t\t\t\t\t\t(layoutReversed ? this.rankTopY[maxRank] : this.rankBottomY[maxRank]);
\t\t\t\tvar jetty = jettys[parallelEdgeCount * 4 + 1 + arrayOffset];
\t\t\t\t
\t\t\t\tif (reversed != layoutReversed)
\t\t\t\t{
\t\t\t\t\tjetty = -jetty;
\t\t\t\t}
\t\t\t\t
\t\t\t\ty += jetty;
\t\t\t\tvar x = jettys[parallelEdgeCount * 4 + arrayOffset];
\t\t\t\t
\t\t\t\tvar modelSource = graph.model.getTerminal(realEdge, true);

\t\t\t\tif (this.layout.isPort(modelSource) && graph.model.getParent(modelSource) == realSource)
\t\t\t\t{
\t\t\t\t\tvar state = graph.view.getState(modelSource);
\t\t\t\t\t
\t\t\t\t\tif (state != null)
\t\t\t\t\t{
\t\t\t\t\t\tx = state.x;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tx = realSource.geometry.x + cell.source.width * modelSource.geometry.x;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (this.orientation == mxConstants.DIRECTION_NORTH
\t\t\t\t\t\t|| this.orientation == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\t\t
\t\t\t\t\tif (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
\t\t\t\t\t{
\t\t\t\t\t\tnewPoints.push(new mxPoint(x, y + jetty));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tnewPoints.push(new mxPoint(y, x));
\t\t\t\t\t
\t\t\t\t\tif (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
\t\t\t\t\t{
\t\t\t\t\t\tnewPoints.push(new mxPoint(y + jetty, x));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// Declare variables to define loop through edge points and 
\t\t\t// change direction if edge is reversed

\t\t\tvar loopStart = cell.x.length - 1;
\t\t\tvar loopLimit = -1;
\t\t\tvar loopDelta = -1;
\t\t\tvar currentRank = cell.maxRank - 1;

\t\t\tif (reversed)
\t\t\t{
\t\t\t\tloopStart = 0;
\t\t\t\tloopLimit = cell.x.length;
\t\t\t\tloopDelta = 1;
\t\t\t\tcurrentRank = cell.minRank + 1;
\t\t\t}
\t\t\t// Reversed edges need the points inserted in
\t\t\t// reverse order
\t\t\tfor (var j = loopStart; (cell.maxRank != cell.minRank) && j != loopLimit; j += loopDelta)
\t\t\t{
\t\t\t\t// The horizontal position in a vertical layout
\t\t\t\tvar positionX = cell.x[j] + offsetX;

\t\t\t\t// Work out the vertical positions in a vertical layout
\t\t\t\t// in the edge buffer channels above and below this rank
\t\t\t\tvar topChannelY = (this.rankTopY[currentRank] + this.rankBottomY[currentRank + 1]) / 2.0;
\t\t\t\tvar bottomChannelY = (this.rankTopY[currentRank - 1] + this.rankBottomY[currentRank]) / 2.0;

\t\t\t\tif (reversed)
\t\t\t\t{
\t\t\t\t\tvar tmp = topChannelY;
\t\t\t\t\ttopChannelY = bottomChannelY;
\t\t\t\t\tbottomChannelY = tmp;
\t\t\t\t}

\t\t\t\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\t\t\t\tthis.orientation == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tnewPoints.push(new mxPoint(positionX, topChannelY));
\t\t\t\t\tnewPoints.push(new mxPoint(positionX, bottomChannelY));
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tnewPoints.push(new mxPoint(topChannelY, positionX));
\t\t\t\t\tnewPoints.push(new mxPoint(bottomChannelY, positionX));
\t\t\t\t}

\t\t\t\tthis.limitX = Math.max(this.limitX, positionX);
\t\t\t\tcurrentRank += loopDelta;
\t\t\t}

\t\t\t// Second jetty of edge
\t\t\tif (jettys != null)
\t\t\t{
\t\t\t\tvar arrayOffset = reversed ? 2 : 0;
\t\t\t\tvar rankY = reversed ?
\t\t\t\t\t\t(layoutReversed ? this.rankTopY[maxRank] : this.rankBottomY[maxRank]) :
\t\t\t\t\t\t\t(layoutReversed ? this.rankBottomY[minRank] : this.rankTopY[minRank]);
\t\t\t\tvar jetty = jettys[parallelEdgeCount * 4 + 3 - arrayOffset];
\t\t\t\t
\t\t\t\tif (reversed != layoutReversed)
\t\t\t\t{
\t\t\t\t\tjetty = -jetty;
\t\t\t\t}
\t\t\t\tvar y = rankY - jetty;
\t\t\t\tvar x = jettys[parallelEdgeCount * 4 + 2 - arrayOffset];
\t\t\t\t
\t\t\t\tvar modelTarget = graph.model.getTerminal(realEdge, false);
\t\t\t\tvar realTarget = this.layout.getVisibleTerminal(realEdge, false);

\t\t\t\tif (this.layout.isPort(modelTarget) && graph.model.getParent(modelTarget) == realTarget)
\t\t\t\t{
\t\t\t\t\tvar state = graph.view.getState(modelTarget);
\t\t\t\t\t
\t\t\t\t\tif (state != null)
\t\t\t\t\t{
\t\t\t\t\t\tx = state.x;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tx = realTarget.geometry.x + cell.target.width * modelTarget.geometry.x;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\t\t\t\t\tthis.orientation == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tif (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
\t\t\t\t\t{
\t\t\t\t\t\tnewPoints.push(new mxPoint(x, y - jetty));
\t\t\t\t\t}

\t\t\t\t\tnewPoints.push(new mxPoint(x, y));
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tif (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
\t\t\t\t\t{
\t\t\t\t\t\tnewPoints.push(new mxPoint(y - jetty, x));
\t\t\t\t\t}

\t\t\t\t\tnewPoints.push(new mxPoint(y, x));
\t\t\t\t}
\t\t\t}

\t\t\tif (cell.isReversed)
\t\t\t{
\t\t\t\tthis.processReversedEdge(cell, realEdge);
\t\t\t}

\t\t\tthis.layout.setEdgePoints(realEdge, newPoints);

\t\t\t// Increase offset so next edge is drawn next to
\t\t\t// this one
\t\t\tif (offsetX == 0.0)
\t\t\t{
\t\t\t\toffsetX = this.parallelEdgeSpacing;
\t\t\t}
\t\t\telse if (offsetX > 0)
\t\t\t{
\t\t\t\toffsetX = -offsetX;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\toffsetX = -offsetX + this.parallelEdgeSpacing;
\t\t\t}
\t\t\t
\t\t\tparallelEdgeCount++;
\t\t}

\t\tcell.temp[0] = 101207;
\t}
};


/**
 * Function: setVertexLocation
 * 
 * Fixes the position of the specified vertex.
 * 
 * Parameters:
 * 
 * cell - the vertex to position
 */
mxCoordinateAssignment.prototype.setVertexLocation = function(cell)
{
\tvar realCell = cell.cell;
\tvar positionX = cell.x[0] - cell.width / 2;
\tvar positionY = cell.y[0] - cell.height / 2;

\tthis.rankTopY[cell.minRank] = Math.min(this.rankTopY[cell.minRank], positionY);
\tthis.rankBottomY[cell.minRank] = Math.max(this.rankBottomY[cell.minRank],
\t\t\tpositionY + cell.height);

\tif (this.orientation == mxConstants.DIRECTION_NORTH ||
\t\tthis.orientation == mxConstants.DIRECTION_SOUTH)
\t{
\t\tthis.layout.setVertexLocation(realCell, positionX, positionY);
\t}
\telse
\t{
\t\tthis.layout.setVertexLocation(realCell, positionY, positionX);
\t}

\tthis.limitX = Math.max(this.limitX, positionX + cell.width);
};

/**
 * Function: processReversedEdge
 * 
 * Hook to add additional processing
 * 
 * Parameters:
 * 
 * edge - the hierarchical model edge
 * realEdge - the real edge in the graph
 */
mxCoordinateAssignment.prototype.processReversedEdge = function(graph, model)
{
\t// hook for subclassers
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSwimlaneOrdering
 * 
 * An implementation of the first stage of the Sugiyama layout. Straightforward
 * longest path calculation of layer assignment
 * 
 * Constructor: mxSwimlaneOrdering
 *
 * Creates a cycle remover for the given internal model.
 */
function mxSwimlaneOrdering(layout)
{
\tthis.layout = layout;
};

/**
 * Extends mxHierarchicalLayoutStage.
 */
mxSwimlaneOrdering.prototype = new mxHierarchicalLayoutStage();
mxSwimlaneOrdering.prototype.constructor = mxSwimlaneOrdering;

/**
 * Variable: layout
 * 
 * Reference to the enclosing <mxHierarchicalLayout>.
 */
mxSwimlaneOrdering.prototype.layout = null;

/**
 * Function: execute
 * 
 * Takes the graph detail and configuration information within the facade
 * and creates the resulting laid out graph within that facade for further
 * use.
 */
mxSwimlaneOrdering.prototype.execute = function(parent)
{
\tvar model = this.layout.getModel();
\tvar seenNodes = new Object();
\tvar unseenNodes = mxUtils.clone(model.vertexMapper, null, true);
\t
\t// Perform a dfs through the internal model. If a cycle is found,
\t// reverse it.
\tvar rootsArray = null;
\t
\tif (model.roots != null)
\t{
\t\tvar modelRoots = model.roots;
\t\trootsArray = [];
\t\t
\t\tfor (var i = 0; i < modelRoots.length; i++)
\t\t{
\t\t\trootsArray[i] = model.vertexMapper.get(modelRoots[i]);
\t\t}
\t}

\tmodel.visit(function(parent, node, connectingEdge, layer, seen)
\t{
\t\t// Check if the cell is in it's own ancestor list, if so
\t\t// invert the connecting edge and reverse the target/source
\t\t// relationship to that edge in the parent and the cell
\t\t// Ancestor hashes only line up within a swimlane
\t\tvar isAncestor = parent != null && parent.swimlaneIndex == node.swimlaneIndex && node.isAncestor(parent);

\t\t// If the source->target swimlane indices go from higher to
\t\t// lower, the edge is reverse
\t\tvar reversedOverSwimlane = parent != null && connectingEdge != null &&
\t\t\t\t\t\tparent.swimlaneIndex < node.swimlaneIndex && connectingEdge.source == node;

\t\tif (isAncestor)
\t\t{
\t\t\tconnectingEdge.invert();
\t\t\tmxUtils.remove(connectingEdge, parent.connectsAsSource);
\t\t\tnode.connectsAsSource.push(connectingEdge);
\t\t\tparent.connectsAsTarget.push(connectingEdge);
\t\t\tmxUtils.remove(connectingEdge, node.connectsAsTarget);
\t\t}
\t\telse if (reversedOverSwimlane)
\t\t{
\t\t\tconnectingEdge.invert();
\t\t\tmxUtils.remove(connectingEdge, parent.connectsAsTarget);
\t\t\tnode.connectsAsTarget.push(connectingEdge);
\t\t\tparent.connectsAsSource.push(connectingEdge);
\t\t\tmxUtils.remove(connectingEdge, node.connectsAsSource);
\t\t}
\t\t
\t\tvar cellId = mxCellPath.create(node.cell);
\t\tseenNodes[cellId] = node;
\t\tdelete unseenNodes[cellId];
\t}, rootsArray, true, null);
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxHierarchicalLayout
 * 
 * A hierarchical layout algorithm.
 * 
 * Constructor: mxHierarchicalLayout
 *
 * Constructs a new hierarchical layout algorithm.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * orientation - Optional constant that defines the orientation of this
 * layout.
 * deterministic - Optional boolean that specifies if this layout should be
 * deterministic. Default is true.
 */
function mxHierarchicalLayout(graph, orientation, deterministic)
{
\tmxGraphLayout.call(this, graph);
\tthis.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH;
\tthis.deterministic = (deterministic != null) ? deterministic : true;
};

var mxHierarchicalEdgeStyle =
{
\tORTHOGONAL: 1,
\tPOLYLINE: 2,
\tSTRAIGHT: 3,
\tCURVE: 4
};

/**
 * Extends mxGraphLayout.
 */
mxHierarchicalLayout.prototype = new mxGraphLayout();
mxHierarchicalLayout.prototype.constructor = mxHierarchicalLayout;

/**
 * Variable: roots
 * 
 * Holds the array of <mxCell> that this layout contains.
 */
mxHierarchicalLayout.prototype.roots = null;

/**
 * Variable: resizeParent
 * 
 * Specifies if the parent should be resized after the layout so that it
 * contains all the child cells. Default is false. See also <parentBorder>.
 */
mxHierarchicalLayout.prototype.resizeParent = false;

/**
 * Variable: maintainParentLocation
 * 
 * Specifies if the parent location should be maintained, so that the
 * top, left corner stays the same before and after execution of
 * the layout. Default is false for backwards compatibility.
 */
mxHierarchicalLayout.prototype.maintainParentLocation = false;

/**
 * Variable: moveParent
 * 
 * Specifies if the parent should be moved if <resizeParent> is enabled.
 * Default is false.
 */
mxHierarchicalLayout.prototype.moveParent = false;

/**
 * Variable: parentBorder
 * 
 * The border to be added around the children if the parent is to be
 * resized using <resizeParent>. Default is 0.
 */
mxHierarchicalLayout.prototype.parentBorder = 0;

/**
 * Variable: intraCellSpacing
 * 
 * The spacing buffer added between cells on the same layer. Default is 30.
 */
mxHierarchicalLayout.prototype.intraCellSpacing = 30;

/**
 * Variable: interRankCellSpacing
 * 
 * The spacing buffer added between cell on adjacent layers. Default is 100.
 */
mxHierarchicalLayout.prototype.interRankCellSpacing = 100;

/**
 * Variable: interHierarchySpacing
 * 
 * The spacing buffer between unconnected hierarchies. Default is 60.
 */
mxHierarchicalLayout.prototype.interHierarchySpacing = 60;

/**
 * Variable: parallelEdgeSpacing
 * 
 * The distance between each parallel edge on each ranks for long edges.
 * Default is 10.
 */
mxHierarchicalLayout.prototype.parallelEdgeSpacing = 10;

/**
 * Variable: orientation
 * 
 * The position of the root node(s) relative to the laid out graph in.
 * Default is <mxConstants.DIRECTION_NORTH>.
 */
mxHierarchicalLayout.prototype.orientation = mxConstants.DIRECTION_NORTH;

/**
 * Variable: fineTuning
 * 
 * Whether or not to perform local optimisations and iterate multiple times
 * through the algorithm. Default is true.
 */
mxHierarchicalLayout.prototype.fineTuning = true;

/**
 * 
 * Variable: tightenToSource
 * 
 * Whether or not to tighten the assigned ranks of vertices up towards
 * the source cells. Default is true.
 */
mxHierarchicalLayout.prototype.tightenToSource = true;

/**
 * Variable: disableEdgeStyle
 * 
 * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are
 * modified by the result. Default is true.
 */
mxHierarchicalLayout.prototype.disableEdgeStyle = true;

/**
 * Variable: traverseAncestors
 * 
 * Whether or not to drill into child cells and layout in reverse
 * group order. This also cause the layout to navigate edges whose 
 * terminal vertices have different parents but are in the same 
 * ancestry chain. Default is true.
 */
mxHierarchicalLayout.prototype.traverseAncestors = true;

/**
 * Variable: model
 * 
 * The internal <mxGraphHierarchyModel> formed of the layout.
 */
mxHierarchicalLayout.prototype.model = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxHierarchicalLayout.prototype.edgesCache = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxHierarchicalLayout.prototype.edgeSourceTermCache = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxHierarchicalLayout.prototype.edgesTargetTermCache = null;

/**
 * Variable: edgeStyle
 * 
 * The style to apply between cell layers to edge segments.
 * Default is <mxHierarchicalEdgeStyle.POLYLINE>.
 */
mxHierarchicalLayout.prototype.edgeStyle = mxHierarchicalEdgeStyle.POLYLINE;

/**
 * Function: getModel
 * 
 * Returns the internal <mxGraphHierarchyModel> for this layout algorithm.
 */
mxHierarchicalLayout.prototype.getModel = function()
{
\treturn this.model;
};

/**
 * Function: execute
 * 
 * Executes the layout for the children of the specified parent.
 * 
 * Parameters:
 * 
 * parent - Parent <mxCell> that contains the children to be laid out.
 * roots - Optional starting roots of the layout.
 */
mxHierarchicalLayout.prototype.execute = function(parent, roots)
{
\tthis.parent = parent;
\tvar model = this.graph.model;
\tthis.edgesCache = new mxDictionary();
\tthis.edgeSourceTermCache = new mxDictionary();
\tthis.edgesTargetTermCache = new mxDictionary();

\tif (roots != null && !(roots instanceof Array))
\t{
\t\troots = [roots];
\t}
\t
\t// If the roots are set and the parent is set, only
\t// use the roots that are some dependent of the that
\t// parent.
\t// If just the root are set, use them as-is
\t// If just the parent is set use it's immediate
\t// children as the initial set

\tif (roots == null && parent == null)
\t{
\t\t// TODO indicate the problem
\t\treturn;
\t}
\t
\t//  Maintaining parent location
\tthis.parentX = null;
\tthis.parentY = null;
\t
\tif (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
\t{
\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tthis.parentX = geo.x;
\t\t\tthis.parentY = geo.y;
\t\t}
\t}
\t
\tif (roots != null)
\t{
\t\tvar rootsCopy = [];

\t\tfor (var i = 0; i < roots.length; i++)
\t\t{
\t\t\tvar ancestor = parent != null ? model.isAncestor(parent, roots[i]) : true;
\t\t\t
\t\t\tif (ancestor && model.isVertex(roots[i]))
\t\t\t{
\t\t\t\trootsCopy.push(roots[i]);
\t\t\t}
\t\t}

\t\tthis.roots = rootsCopy;
\t}
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tthis.run(parent);
\t\t
\t\tif (this.resizeParent && !this.graph.isCellCollapsed(parent))
\t\t{
\t\t\tthis.graph.updateGroupBounds([parent], this.parentBorder, this.moveParent);
\t\t}
\t\t
\t\t// Maintaining parent location
\t\tif (this.parentX != null && this.parentY != null)
\t\t{
\t\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tgeo = geo.clone();
\t\t\t\tgeo.x = this.parentX;
\t\t\t\tgeo.y = this.parentY;
\t\t\t\tmodel.setGeometry(parent, geo);
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: findRoots
 * 
 * Returns all visible children in the given parent which do not have
 * incoming edges. If the result is empty then the children with the
 * maximum difference between incoming and outgoing edges are returned.
 * This takes into account edges that are being promoted to the given
 * root due to invisible children or collapsed cells.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be checked.
 * vertices - array of vertices to limit search to
 */
mxHierarchicalLayout.prototype.findRoots = function(parent, vertices)
{
\tvar roots = [];
\t
\tif (parent != null && vertices != null)
\t{
\t\tvar model = this.graph.model;
\t\tvar best = null;
\t\tvar maxDiff = -100000;
\t\t
\t\tfor (var i in vertices)
\t\t{
\t\t\tvar cell = vertices[i];

\t\t\tif (model.isVertex(cell) && this.graph.isCellVisible(cell))
\t\t\t{
\t\t\t\tvar conns = this.getEdges(cell);
\t\t\t\tvar fanOut = 0;
\t\t\t\tvar fanIn = 0;

\t\t\t\tfor (var k = 0; k < conns.length; k++)
\t\t\t\t{
\t\t\t\t\tvar src = this.getVisibleTerminal(conns[k], true);

\t\t\t\t\tif (src == cell)
\t\t\t\t\t{
\t\t\t\t\t\tfanOut++;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tfanIn++;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (fanIn == 0 && fanOut > 0)
\t\t\t\t{
\t\t\t\t\troots.push(cell);
\t\t\t\t}

\t\t\t\tvar diff = fanOut - fanIn;

\t\t\t\tif (diff > maxDiff)
\t\t\t\t{
\t\t\t\t\tmaxDiff = diff;
\t\t\t\t\tbest = cell;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (roots.length == 0 && best != null)
\t\t{
\t\t\troots.push(best);
\t\t}
\t}
\t
\treturn roots;
};

/**
 * Function: getEdges
 * 
 * Returns the connected edges for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose edges should be returned.
 */
mxHierarchicalLayout.prototype.getEdges = function(cell)
{
\tvar cachedEdges = this.edgesCache.get(cell);
\t
\tif (cachedEdges != null)
\t{
\t\treturn cachedEdges;
\t}

\tvar model = this.graph.model;
\tvar edges = [];
\tvar isCollapsed = this.graph.isCellCollapsed(cell);
\tvar childCount = model.getChildCount(cell);

\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(cell, i);

\t\tif (this.isPort(child))
\t\t{
\t\t\tedges = edges.concat(model.getEdges(child, true, true));
\t\t}
\t\telse if (isCollapsed || !this.graph.isCellVisible(child))
\t\t{
\t\t\tedges = edges.concat(model.getEdges(child, true, true));
\t\t}
\t}

\tedges = edges.concat(model.getEdges(cell, true, true));
\tvar result = [];
\t
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar source = this.getVisibleTerminal(edges[i], true);
\t\tvar target = this.getVisibleTerminal(edges[i], false);
\t\t
\t\tif ((source == target) ||
\t\t\t\t((source != target) &&
\t\t\t\t\t\t((target == cell && (this.parent == null || this.isAncestor(this.parent, source, this.traverseAncestors))) ||
\t\t\t\t\t\t \t(source == cell && (this.parent == null || this.isAncestor(this.parent, target, this.traverseAncestors))))))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\tthis.edgesCache.put(cell, result);

\treturn result;
};

/**
 * Function: getVisibleTerminal
 * 
 * Helper function to return visible terminal for edge allowing for ports
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose edges should be returned.
 * source - Boolean that specifies whether the source or target terminal is to be returned
 */
mxHierarchicalLayout.prototype.getVisibleTerminal = function(edge, source)
{
\tvar terminalCache = this.edgesTargetTermCache;
\t
\tif (source)
\t{
\t\tterminalCache = this.edgeSourceTermCache;
\t}

\tvar term = terminalCache.get(edge);

\tif (term != null)
\t{
\t\treturn term;
\t}

\tvar state = this.graph.view.getState(edge);
\t
\tvar terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
\t
\tif (terminal == null)
\t{
\t\tterminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
\t}

\tif (terminal != null)
\t{
\t\tif (this.isPort(terminal))
\t\t{
\t\t\tterminal = this.graph.model.getParent(terminal);
\t\t}
\t\t
\t\tterminalCache.put(edge, terminal);
\t}

\treturn terminal;
};

/**
 * Function: run
 * 
 * The API method used to exercise the layout upon the graph description
 * and produce a separate description of the vertex position and edge
 * routing changes made. It runs each stage of the layout that has been
 * created.
 */
mxHierarchicalLayout.prototype.run = function(parent)
{
\t// Separate out unconnected hierarchies
\tvar hierarchyVertices = [];
\tvar allVertexSet = [];

\tif (this.roots == null && parent != null)
\t{
\t\tvar filledVertexSet = Object();
\t\tthis.filterDescendants(parent, filledVertexSet);

\t\tthis.roots = [];
\t\tvar filledVertexSetEmpty = true;

\t\t// Poor man's isSetEmpty
\t\tfor (var key in filledVertexSet)
\t\t{
\t\t\tif (filledVertexSet[key] != null)
\t\t\t{
\t\t\t\tfilledVertexSetEmpty = false;
\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\twhile (!filledVertexSetEmpty)
\t\t{
\t\t\tvar candidateRoots = this.findRoots(parent, filledVertexSet);
\t\t\t
\t\t\t// If the candidate root is an unconnected group cell, remove it from
\t\t\t// the layout. We may need a custom set that holds such groups and forces
\t\t\t// them to be processed for resizing and/or moving.
\t\t\t

\t\t\tfor (var i = 0; i < candidateRoots.length; i++)
\t\t\t{
\t\t\t\tvar vertexSet = Object();
\t\t\t\thierarchyVertices.push(vertexSet);

\t\t\t\tthis.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet,
\t\t\t\t\t\thierarchyVertices, filledVertexSet);
\t\t\t}

\t\t\tfor (var i = 0; i < candidateRoots.length; i++)
\t\t\t{
\t\t\t\tthis.roots.push(candidateRoots[i]);
\t\t\t}
\t\t\t
\t\t\tfilledVertexSetEmpty = true;
\t\t\t
\t\t\t// Poor man's isSetEmpty
\t\t\tfor (var key in filledVertexSet)
\t\t\t{
\t\t\t\tif (filledVertexSet[key] != null)
\t\t\t\t{
\t\t\t\t\tfilledVertexSetEmpty = false;
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\t// Find vertex set as directed traversal from roots

\t\tfor (var i = 0; i < this.roots.length; i++)
\t\t{
\t\t\tvar vertexSet = Object();
\t\t\thierarchyVertices.push(vertexSet);

\t\t\tthis.traverse(this.roots[i], true, null, allVertexSet, vertexSet,
\t\t\t\t\thierarchyVertices, null);
\t\t}
\t}

\t// Iterate through the result removing parents who have children in this layout
\t
\t// Perform a layout for each seperate hierarchy
\t// Track initial coordinate x-positioning
\tvar initialX = 0;

\tfor (var i = 0; i < hierarchyVertices.length; i++)
\t{
\t\tvar vertexSet = hierarchyVertices[i];
\t\tvar tmp = [];
\t\t
\t\tfor (var key in vertexSet)
\t\t{
\t\t\ttmp.push(vertexSet[key]);
\t\t}
\t\t
\t\tthis.model = new mxGraphHierarchyModel(this, tmp, this.roots,
\t\t\tparent, this.tightenToSource);

\t\tthis.cycleStage(parent);
\t\tthis.layeringStage();
\t\t
\t\tthis.crossingStage(parent);
\t\tinitialX = this.placementStage(initialX, parent);
\t}
};

/**
 * Function: filterDescendants
 * 
 * Creates an array of descendant cells
 */
mxHierarchicalLayout.prototype.filterDescendants = function(cell, result)
{
\tvar model = this.graph.model;

\tif (model.isVertex(cell) && cell != this.parent && this.graph.isCellVisible(cell))
\t{
\t\tresult[mxObjectIdentity.get(cell)] = cell;
\t}

\tif (this.traverseAncestors || cell == this.parent
\t\t\t&& this.graph.isCellVisible(cell))
\t{
\t\tvar childCount = model.getChildCount(cell);

\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(cell, i);
\t\t\t
\t\t\t// Ignore ports in the layout vertex list, they are dealt with
\t\t\t// in the traversal mechanisms
\t\t\tif (!this.isPort(child))
\t\t\t{
\t\t\t\tthis.filterDescendants(child, result);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isPort
 * 
 * Returns true if the given cell is a \"port\", that is, when connecting to
 * it, its parent is the connecting vertex in terms of graph traversal
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the port.
 */
mxHierarchicalLayout.prototype.isPort = function(cell)
{
\tif (cell != null && cell.geometry != null)
\t{
\t\treturn cell.geometry.relative;
\t}
\telse
\t{
\t\treturn false;
\t}
};

/**
 * Function: getEdgesBetween
 * 
 * Returns the edges between the given source and target. This takes into
 * account collapsed and invisible cells and ports.
 * 
 * Parameters:
 * 
 * source -
 * target -
 * directed -
 */
mxHierarchicalLayout.prototype.getEdgesBetween = function(source, target, directed)
{
\tdirected = (directed != null) ? directed : false;
\tvar edges = this.getEdges(source);
\tvar result = [];

\t// Checks if the edge is connected to the correct
\t// cell and returns the first match
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar src = this.getVisibleTerminal(edges[i], true);
\t\tvar trg = this.getVisibleTerminal(edges[i], false);

\t\tif ((src == source && trg == target) || (!directed && src == target && trg == source))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\treturn result;
};

/**
 * Traverses the (directed) graph invoking the given function for each
 * visited vertex and edge. The function is invoked with the current vertex
 * and the incoming edge as a parameter. This implementation makes sure
 * each vertex is only visited once. The function may return false if the
 * traversal should stop at the given vertex.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> that represents the vertex where the traversal starts.
 * directed - boolean indicating if edges should only be traversed
 * from source to target. Default is true.
 * edge - Optional <mxCell> that represents the incoming edge. This is
 * null for the first step of the traversal.
 * allVertices - Array of cell paths for the visited cells.
 */
mxHierarchicalLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp,
\t\t\t\t\t\t\t\t\t\t\thierarchyVertices, filledVertexSet)
{
\tif (vertex != null && allVertices != null)
\t{
\t\t// Has this vertex been seen before in any traversal
\t\t// And if the filled vertex set is populated, only 
\t\t// process vertices in that it contains
\t\tvar vertexID = mxObjectIdentity.get(vertex);
\t\t
\t\tif ((allVertices[vertexID] == null)
\t\t\t\t&& (filledVertexSet == null ? true : filledVertexSet[vertexID] != null))
\t\t{
\t\t\tif (currentComp[vertexID] == null)
\t\t\t{
\t\t\t\tcurrentComp[vertexID] = vertex;
\t\t\t}
\t\t\tif (allVertices[vertexID] == null)
\t\t\t{
\t\t\t\tallVertices[vertexID] = vertex;
\t\t\t}

\t\t\tif (filledVertexSet !== null)
\t\t\t{
\t\t\t\tdelete filledVertexSet[vertexID];
\t\t\t}

\t\t\tvar edges = this.getEdges(vertex);
\t\t\tvar edgeIsSource = [];

\t\t\tfor (var i = 0; i < edges.length; i++)
\t\t\t{
\t\t\t\tedgeIsSource[i] = (this.getVisibleTerminal(edges[i], true) == vertex);
\t\t\t}

\t\t\tfor (var i = 0; i < edges.length; i++)
\t\t\t{
\t\t\t\tif (!directed || edgeIsSource[i])
\t\t\t\t{
\t\t\t\t\tvar next = this.getVisibleTerminal(edges[i], !edgeIsSource[i]);
\t\t\t\t\t
\t\t\t\t\t// Check whether there are more edges incoming from the target vertex than outgoing
\t\t\t\t\t// The hierarchical model treats bi-directional parallel edges as being sourced
\t\t\t\t\t// from the more \"sourced\" terminal. If the directions are equal in number, the direction
\t\t\t\t\t// is that of the natural direction from the roots of the layout.
\t\t\t\t\t// The checks below are slightly more verbose than need be for performance reasons
\t\t\t\t\tvar netCount = 1;

\t\t\t\t\tfor (var j = 0; j < edges.length; j++)
\t\t\t\t\t{
\t\t\t\t\t\tif (j == i)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar isSource2 = edgeIsSource[j];
\t\t\t\t\t\t\tvar otherTerm = this.getVisibleTerminal(edges[j], !isSource2);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (otherTerm == next)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (isSource2)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tnetCount++;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tnetCount--;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\tif (netCount >= 0)
\t\t\t\t\t{
\t\t\t\t\t\tcurrentComp = this.traverse(next, directed, edges[i], allVertices,
\t\t\t\t\t\t\tcurrentComp, hierarchyVertices,
\t\t\t\t\t\t\tfilledVertexSet);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (currentComp[vertexID] == null)
\t\t\t{
\t\t\t\t// We've seen this vertex before, but not in the current component
\t\t\t\t// This component and the one it's in need to be merged

\t\t\t\tfor (var i = 0; i < hierarchyVertices.length; i++)
\t\t\t\t{
\t\t\t\t\tvar comp = hierarchyVertices[i];

\t\t\t\t\tif (comp[vertexID] != null)
\t\t\t\t\t{
\t\t\t\t\t\tfor (var key in comp)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrentComp[key] = comp[key];
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// Remove the current component from the hierarchy set
\t\t\t\t\t\thierarchyVertices.splice(i, 1);
\t\t\t\t\t\treturn currentComp;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn currentComp;
};

/**
 * Function: cycleStage
 * 
 * Executes the cycle stage using mxMinimumCycleRemover.
 */
mxHierarchicalLayout.prototype.cycleStage = function(parent)
{
\tvar cycleStage = new mxMinimumCycleRemover(this);
\tcycleStage.execute(parent);
};

/**
 * Function: layeringStage
 * 
 * Implements first stage of a Sugiyama layout.
 */
mxHierarchicalLayout.prototype.layeringStage = function()
{
\tthis.model.initialRank();
\tthis.model.fixRanks();
};

/**
 * Function: crossingStage
 * 
 * Executes the crossing stage using mxMedianHybridCrossingReduction.
 */
mxHierarchicalLayout.prototype.crossingStage = function(parent)
{
\tvar crossingStage = new mxMedianHybridCrossingReduction(this);
\tcrossingStage.execute(parent);
};

/**
 * Function: placementStage
 * 
 * Executes the placement stage using mxCoordinateAssignment.
 */
mxHierarchicalLayout.prototype.placementStage = function(initialX, parent)
{
\tvar placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing,
\t\t\tthis.interRankCellSpacing, this.orientation, initialX,
\t\t\tthis.parallelEdgeSpacing);
\tplacementStage.fineTuning = this.fineTuning;
\tplacementStage.execute(parent);
\t
\treturn placementStage.limitX + this.interHierarchySpacing;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSwimlaneLayout
 * 
 * A hierarchical layout algorithm.
 * 
 * Constructor: mxSwimlaneLayout
 *
 * Constructs a new hierarchical layout algorithm.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * orientation - Optional constant that defines the orientation of this
 * layout.
 * deterministic - Optional boolean that specifies if this layout should be
 * deterministic. Default is true.
 */
function mxSwimlaneLayout(graph, orientation, deterministic)
{
\tmxGraphLayout.call(this, graph);
\tthis.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH;
\tthis.deterministic = (deterministic != null) ? deterministic : true;
};

/**
 * Extends mxGraphLayout.
 */
mxSwimlaneLayout.prototype = new mxGraphLayout();
mxSwimlaneLayout.prototype.constructor = mxSwimlaneLayout;

/**
 * Variable: roots
 * 
 * Holds the array of <mxCell> that this layout contains.
 */
mxSwimlaneLayout.prototype.roots = null;

/**
 * Variable: swimlanes
 * 
 * Holds the array of <mxCell> of the ordered swimlanes to lay out
 */
mxSwimlaneLayout.prototype.swimlanes = null;

/**
 * Variable: dummyVertexWidth
 * 
 * The cell width of any dummy vertices inserted
 */
mxSwimlaneLayout.prototype.dummyVertexWidth = 50;

/**
 * Variable: resizeParent
 * 
 * Specifies if the parent should be resized after the layout so that it
 * contains all the child cells. Default is false. See also <parentBorder>.
 */
mxSwimlaneLayout.prototype.resizeParent = false;

/**
 * Variable: maintainParentLocation
 * 
 * Specifies if the parent location should be maintained, so that the
 * top, left corner stays the same before and after execution of
 * the layout. Default is false for backwards compatibility.
 */
mxSwimlaneLayout.prototype.maintainParentLocation = false;

/**
 * Variable: moveParent
 * 
 * Specifies if the parent should be moved if <resizeParent> is enabled.
 * Default is false.
 */
mxSwimlaneLayout.prototype.moveParent = false;

/**
 * Variable: parentBorder
 * 
 * The border to be added around the children if the parent is to be
 * resized using <resizeParent>. Default is 30.
 */
mxSwimlaneLayout.prototype.parentBorder = 30;

/**
 * Variable: intraCellSpacing
 * 
 * The spacing buffer added between cells on the same layer. Default is 30.
 */
mxSwimlaneLayout.prototype.intraCellSpacing = 30;

/**
 * Variable: interRankCellSpacing
 * 
 * The spacing buffer added between cell on adjacent layers. Default is 100.
 */
mxSwimlaneLayout.prototype.interRankCellSpacing = 100;

/**
 * Variable: interHierarchySpacing
 * 
 * The spacing buffer between unconnected hierarchies. Default is 60.
 */
mxSwimlaneLayout.prototype.interHierarchySpacing = 60;

/**
 * Variable: parallelEdgeSpacing
 * 
 * The distance between each parallel edge on each ranks for long edges.
 * Default is 10.
 */
mxSwimlaneLayout.prototype.parallelEdgeSpacing = 10;

/**
 * Variable: orientation
 * 
 * The position of the root node(s) relative to the laid out graph in.
 * Default is <mxConstants.DIRECTION_NORTH>.
 */
mxSwimlaneLayout.prototype.orientation = mxConstants.DIRECTION_NORTH;

/**
 * Variable: fineTuning
 * 
 * Whether or not to perform local optimisations and iterate multiple times
 * through the algorithm. Default is true.
 */
mxSwimlaneLayout.prototype.fineTuning = true;

/**
 * Variable: tightenToSource
 * 
 * Whether or not to tighten the assigned ranks of vertices up towards
 * the source cells. Default is true.
 */
mxSwimlaneLayout.prototype.tightenToSource = true;

/**
 * Variable: disableEdgeStyle
 * 
 * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are
 * modified by the result. Default is true.
 */
mxSwimlaneLayout.prototype.disableEdgeStyle = true;

/**
 * Variable: traverseAncestors
 * 
 * Whether or not to drill into child cells and layout in reverse
 * group order. This also cause the layout to navigate edges whose 
 * terminal vertices have different parents but are in the same
 * ancestry chain. Default is true.
 */
mxSwimlaneLayout.prototype.traverseAncestors = true;

/**
 * Variable: model
 * 
 * The internal <mxSwimlaneModel> formed of the layout.
 */
mxSwimlaneLayout.prototype.model = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxSwimlaneLayout.prototype.edgesCache = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxHierarchicalLayout.prototype.edgeSourceTermCache = null;

/**
 * Variable: edgesSet
 * 
 * A cache of edges whose source terminal is the key
 */
mxHierarchicalLayout.prototype.edgesTargetTermCache = null;

/**
 * Variable: edgeStyle
 * 
 * The style to apply between cell layers to edge segments.
 * Default is <mxHierarchicalEdgeStyle.POLYLINE>.
 */
mxHierarchicalLayout.prototype.edgeStyle = mxHierarchicalEdgeStyle.POLYLINE;

/**
 * Function: getModel
 * 
 * Returns the internal <mxSwimlaneModel> for this layout algorithm.
 */
mxSwimlaneLayout.prototype.getModel = function()
{
\treturn this.model;
};

/**
 * Function: execute
 * 
 * Executes the layout for the children of the specified parent.
 * 
 * Parameters:
 * 
 * parent - Parent <mxCell> that contains the children to be laid out.
 * swimlanes - Ordered array of swimlanes to be laid out
 */
mxSwimlaneLayout.prototype.execute = function(parent, swimlanes)
{
\tthis.parent = parent;
\tvar model = this.graph.model;
\tthis.edgesCache = new mxDictionary();
\tthis.edgeSourceTermCache = new mxDictionary();
\tthis.edgesTargetTermCache = new mxDictionary();

\t// If the roots are set and the parent is set, only
\t// use the roots that are some dependent of the that
\t// parent.
\t// If just the root are set, use them as-is
\t// If just the parent is set use it's immediate
\t// children as the initial set

\tif (swimlanes == null || swimlanes.length < 1)
\t{
\t\t// TODO indicate the problem
\t\treturn;
\t}

\tif (parent == null)
\t{
\t\tparent = model.getParent(swimlanes[0]);
\t}

\t//  Maintaining parent location
\tthis.parentX = null;
\tthis.parentY = null;
\t
\tif (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
\t{
\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tthis.parentX = geo.x;
\t\t\tthis.parentY = geo.y;
\t\t}
\t}

\tthis.swimlanes = swimlanes;
\tvar dummyVertices = [];
\t// Check the swimlanes all have vertices
\t// in them
\tfor (var i = 0; i < swimlanes.length; i++)
\t{
\t\tvar children = this.graph.getChildCells(swimlanes[i]);
\t\t
\t\tif (children == null || children.length == 0)
\t\t{
\t\t\tvar vertex = this.graph.insertVertex(swimlanes[i], null, null, 0, 0, this.dummyVertexWidth, 0);
\t\t\tdummyVertices.push(vertex);
\t\t}
\t}
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tthis.run(parent);
\t\t
\t\tif (this.resizeParent && !this.graph.isCellCollapsed(parent))
\t\t{
\t\t\tthis.graph.updateGroupBounds([parent], this.parentBorder, this.moveParent);
\t\t}
\t\t
\t\t// Maintaining parent location
\t\tif (this.parentX != null && this.parentY != null)
\t\t{
\t\t\tvar geo = this.graph.getCellGeometry(parent);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tgeo = geo.clone();
\t\t\t\tgeo.x = this.parentX;
\t\t\t\tgeo.y = this.parentY;
\t\t\t\tmodel.setGeometry(parent, geo);
\t\t\t}
\t\t}

\t\tthis.graph.removeCells(dummyVertices);
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: updateGroupBounds
 * 
 * Updates the bounds of the given array of groups so that it includes
 * all child vertices.
 * 
 */
mxSwimlaneLayout.prototype.updateGroupBounds = function()
{
\t// Get all vertices and edge in the layout
\tvar cells = [];
\tvar model = this.model;
\t
\tfor (var key in model.edgeMapper)
\t{
\t\tvar edge = model.edgeMapper[key];
\t\t
\t\tfor (var i = 0; i < edge.edges.length; i++)
\t\t{
\t\t\tcells.push(edge.edges[i]);
\t\t}
\t}
\t
\tvar layoutBounds = this.graph.getBoundingBoxFromGeometry(cells, true);
\tvar childBounds = [];

\tfor (var i = 0; i < this.swimlanes.length; i++)
\t{
\t\tvar lane = this.swimlanes[i];
\t\tvar geo = this.graph.getCellGeometry(lane);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tvar children = this.graph.getChildCells(lane);
\t\t\t
\t\t\tvar size = (this.graph.isSwimlane(lane)) ?
\t\t\t\t\tthis.graph.getStartSize(lane) : new mxRectangle();

\t\t\tvar bounds = this.graph.getBoundingBoxFromGeometry(children);
\t\t\tchildBounds[i] = bounds;
\t\t\tvar childrenY = bounds.y + geo.y - size.height - this.parentBorder;
\t\t\tvar maxChildrenY = bounds.y + geo.y + bounds.height;

\t\t\tif (layoutBounds == null)
\t\t\t{
\t\t\t\tlayoutBounds = new mxRectangle(0, childrenY, 0, maxChildrenY - childrenY);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tlayoutBounds.y = Math.min(layoutBounds.y, childrenY);
\t\t\t\tvar maxY = Math.max(layoutBounds.y + layoutBounds.height, maxChildrenY);
\t\t\t\tlayoutBounds.height = maxY - layoutBounds.y;
\t\t\t}
\t\t}
\t}

\t
\tfor (var i = 0; i < this.swimlanes.length; i++)
\t{
\t\tvar lane = this.swimlanes[i];
\t\tvar geo = this.graph.getCellGeometry(lane);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tvar children = this.graph.getChildCells(lane);
\t\t\t
\t\t\tvar size = (this.graph.isSwimlane(lane)) ?
\t\t\t\t\tthis.graph.getStartSize(lane) : new mxRectangle();

\t\t\tvar newGeo = geo.clone();
\t\t\t
\t\t\tvar leftGroupBorder = (i == 0) ? this.parentBorder : this.interRankCellSpacing/2;
\t\t\tvar w = size.width + leftGroupBorder;
\t\t\tvar x = childBounds[i].x - w;
\t\t\tvar y = layoutBounds.y - this.parentBorder;

\t\t\tnewGeo.x += x;
\t\t\tnewGeo.y = y;
\t\t\t
\t\t\tnewGeo.width = childBounds[i].width + w + this.interRankCellSpacing/2;
\t\t\tnewGeo.height = layoutBounds.height + size.height + 2 * this.parentBorder;
\t\t\t
\t\t\tthis.graph.model.setGeometry(lane, newGeo);
\t\t\tthis.graph.moveCells(children, -x, geo.y - y);
\t\t}
\t}
};

/**
 * Function: findRoots
 * 
 * Returns all visible children in the given parent which do not have
 * incoming edges. If the result is empty then the children with the
 * maximum difference between incoming and outgoing edges are returned.
 * This takes into account edges that are being promoted to the given
 * root due to invisible children or collapsed cells.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be checked.
 * vertices - array of vertices to limit search to
 */
mxSwimlaneLayout.prototype.findRoots = function(parent, vertices)
{
\tvar roots = [];
\t
\tif (parent != null && vertices != null)
\t{
\t\tvar model = this.graph.model;
\t\tvar best = null;
\t\tvar maxDiff = -100000;
\t\t
\t\tfor (var i in vertices)
\t\t{
\t\t\tvar cell = vertices[i];

\t\t\tif (cell != null && model.isVertex(cell) && this.graph.isCellVisible(cell) && model.isAncestor(parent, cell))
\t\t\t{
\t\t\t\tvar conns = this.getEdges(cell);
\t\t\t\tvar fanOut = 0;
\t\t\t\tvar fanIn = 0;

\t\t\t\tfor (var k = 0; k < conns.length; k++)
\t\t\t\t{
\t\t\t\t\tvar src = this.getVisibleTerminal(conns[k], true);

\t\t\t\t\tif (src == cell)
\t\t\t\t\t{
\t\t\t\t\t\t// Only count connection within this swimlane
\t\t\t\t\t\tvar other = this.getVisibleTerminal(conns[k], false);
\t\t\t\t\t\t
\t\t\t\t\t\tif (model.isAncestor(parent, other))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tfanOut++;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse if (model.isAncestor(parent, src))
\t\t\t\t\t{
\t\t\t\t\t\tfanIn++;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (fanIn == 0 && fanOut > 0)
\t\t\t\t{
\t\t\t\t\troots.push(cell);
\t\t\t\t}

\t\t\t\tvar diff = fanOut - fanIn;

\t\t\t\tif (diff > maxDiff)
\t\t\t\t{
\t\t\t\t\tmaxDiff = diff;
\t\t\t\t\tbest = cell;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (roots.length == 0 && best != null)
\t\t{
\t\t\troots.push(best);
\t\t}
\t}
\t
\treturn roots;
};

/**
 * Function: getEdges
 * 
 * Returns the connected edges for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose edges should be returned.
 */
mxSwimlaneLayout.prototype.getEdges = function(cell)
{
\tvar cachedEdges = this.edgesCache.get(cell);
\t
\tif (cachedEdges != null)
\t{
\t\treturn cachedEdges;
\t}

\tvar model = this.graph.model;
\tvar edges = [];
\tvar isCollapsed = this.graph.isCellCollapsed(cell);
\tvar childCount = model.getChildCount(cell);

\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(cell, i);

\t\tif (this.isPort(child))
\t\t{
\t\t\tedges = edges.concat(model.getEdges(child, true, true));
\t\t}
\t\telse if (isCollapsed || !this.graph.isCellVisible(child))
\t\t{
\t\t\tedges = edges.concat(model.getEdges(child, true, true));
\t\t}
\t}

\tedges = edges.concat(model.getEdges(cell, true, true));
\tvar result = [];
\t
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar source = this.getVisibleTerminal(edges[i], true);
\t\tvar target = this.getVisibleTerminal(edges[i], false);
\t\t
\t\tif ((source == target) || ((source != target) && ((target == cell && (this.parent == null || this.graph.isValidAncestor(source, this.parent, this.traverseAncestors))) ||
\t\t\t(source == cell && (this.parent == null ||
\t\t\t\t\tthis.graph.isValidAncestor(target, this.parent, this.traverseAncestors))))))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\tthis.edgesCache.put(cell, result);

\treturn result;
};

/**
 * Function: getVisibleTerminal
 * 
 * Helper function to return visible terminal for edge allowing for ports
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose edges should be returned.
 * source - Boolean that specifies whether the source or target terminal is to be returned
 */
mxSwimlaneLayout.prototype.getVisibleTerminal = function(edge, source)
{
\tvar terminalCache = this.edgesTargetTermCache;
\t
\tif (source)
\t{
\t\tterminalCache = this.edgeSourceTermCache;
\t}

\tvar term = terminalCache.get(edge);

\tif (term != null)
\t{
\t\treturn term;
\t}

\tvar state = this.graph.view.getState(edge);
\t
\tvar terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
\t
\tif (terminal == null)
\t{
\t\tterminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
\t}

\tif (terminal != null)
\t{
\t\tif (this.isPort(terminal))
\t\t{
\t\t\tterminal = this.graph.model.getParent(terminal);
\t\t}
\t\t
\t\tterminalCache.put(edge, terminal);
\t}

\treturn terminal;
};

/**
 * Function: run
 * 
 * The API method used to exercise the layout upon the graph description
 * and produce a separate description of the vertex position and edge
 * routing changes made. It runs each stage of the layout that has been
 * created.
 */
mxSwimlaneLayout.prototype.run = function(parent)
{
\t// Separate out unconnected hierarchies
\tvar hierarchyVertices = [];
\tvar allVertexSet = Object();

\tif (this.swimlanes != null && this.swimlanes.length > 0 && parent != null)
\t{
\t\tvar filledVertexSet = Object();
\t\t
\t\tfor (var i = 0; i < this.swimlanes.length; i++)
\t\t{
\t\t\tthis.filterDescendants(this.swimlanes[i], filledVertexSet);
\t\t}

\t\tthis.roots = [];
\t\tvar filledVertexSetEmpty = true;

\t\t// Poor man's isSetEmpty
\t\tfor (var key in filledVertexSet)
\t\t{
\t\t\tif (filledVertexSet[key] != null)
\t\t\t{
\t\t\t\tfilledVertexSetEmpty = false;
\t\t\t\tbreak;
\t\t\t}
\t\t}

\t\t// Only test for candidates in each swimlane in order
\t\tvar laneCounter = 0;

\t\twhile (!filledVertexSetEmpty && laneCounter < this.swimlanes.length)
\t\t{
\t\t\tvar candidateRoots = this.findRoots(this.swimlanes[laneCounter], filledVertexSet);
\t\t\t
\t\t\tif (candidateRoots.length == 0)
\t\t\t{
\t\t\t\tlaneCounter++;
\t\t\t\tcontinue;
\t\t\t}
\t\t\t
\t\t\t// If the candidate root is an unconnected group cell, remove it from
\t\t\t// the layout. We may need a custom set that holds such groups and forces
\t\t\t// them to be processed for resizing and/or moving.
\t\t\tfor (var i = 0; i < candidateRoots.length; i++)
\t\t\t{
\t\t\t\tvar vertexSet = Object();
\t\t\t\thierarchyVertices.push(vertexSet);

\t\t\t\tthis.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet,
\t\t\t\t\t\thierarchyVertices, filledVertexSet, laneCounter);
\t\t\t}

\t\t\tfor (var i = 0; i < candidateRoots.length; i++)
\t\t\t{
\t\t\t\tthis.roots.push(candidateRoots[i]);
\t\t\t}
\t\t\t
\t\t\tfilledVertexSetEmpty = true;
\t\t\t
\t\t\t// Poor man's isSetEmpty
\t\t\tfor (var key in filledVertexSet)
\t\t\t{
\t\t\t\tif (filledVertexSet[key] != null)
\t\t\t\t{
\t\t\t\t\tfilledVertexSetEmpty = false;
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\t// Find vertex set as directed traversal from roots

\t\tfor (var i = 0; i < this.roots.length; i++)
\t\t{
\t\t\tvar vertexSet = Object();
\t\t\thierarchyVertices.push(vertexSet);

\t\t\tthis.traverse(this.roots[i], true, null, allVertexSet, vertexSet,
\t\t\t\t\thierarchyVertices, null);
\t\t}
\t}

\tvar tmp = [];
\t
\tfor (var key in allVertexSet)
\t{
\t\ttmp.push(allVertexSet[key]);
\t}
\t
\tthis.model = new mxSwimlaneModel(this, tmp, this.roots,
\t\tparent, this.tightenToSource);

\tthis.cycleStage(parent);
\tthis.layeringStage();
\t
\tthis.crossingStage(parent);
\tthis.placementStage(0, parent);
};

/**
 * Function: filterDescendants
 * 
 * Creates an array of descendant cells
 */
mxSwimlaneLayout.prototype.filterDescendants = function(cell, result)
{
\tvar model = this.graph.model;

\tif (model.isVertex(cell) && cell != this.parent && model.getParent(cell) != this.parent && this.graph.isCellVisible(cell))
\t{
\t\tresult[mxObjectIdentity.get(cell)] = cell;
\t}

\tif (this.traverseAncestors || cell == this.parent
\t\t\t&& this.graph.isCellVisible(cell))
\t{
\t\tvar childCount = model.getChildCount(cell);

\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(cell, i);
\t\t\t
\t\t\t// Ignore ports in the layout vertex list, they are dealt with
\t\t\t// in the traversal mechanisms
\t\t\tif (!this.isPort(child))
\t\t\t{
\t\t\t\tthis.filterDescendants(child, result);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isPort
 * 
 * Returns true if the given cell is a \"port\", that is, when connecting to
 * it, its parent is the connecting vertex in terms of graph traversal
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the port.
 */
mxSwimlaneLayout.prototype.isPort = function(cell)
{
\tif (cell.geometry.relative)
\t{
\t\treturn true;
\t}
\t
\treturn false;
};

/**
 * Function: getEdgesBetween
 * 
 * Returns the edges between the given source and target. This takes into
 * account collapsed and invisible cells and ports.
 * 
 * Parameters:
 * 
 * source -
 * target -
 * directed -
 */
mxSwimlaneLayout.prototype.getEdgesBetween = function(source, target, directed)
{
\tdirected = (directed != null) ? directed : false;
\tvar edges = this.getEdges(source);
\tvar result = [];

\t// Checks if the edge is connected to the correct
\t// cell and returns the first match
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar src = this.getVisibleTerminal(edges[i], true);
\t\tvar trg = this.getVisibleTerminal(edges[i], false);

\t\tif ((src == source && trg == target) || (!directed && src == target && trg == source))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\treturn result;
};

/**
 * Traverses the (directed) graph invoking the given function for each
 * visited vertex and edge. The function is invoked with the current vertex
 * and the incoming edge as a parameter. This implementation makes sure
 * each vertex is only visited once. The function may return false if the
 * traversal should stop at the given vertex.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> that represents the vertex where the traversal starts.
 * directed - boolean indicating if edges should only be traversed
 * from source to target. Default is true.
 * edge - Optional <mxCell> that represents the incoming edge. This is
 * null for the first step of the traversal.
 * allVertices - Array of cell paths for the visited cells.
 * swimlaneIndex - the laid out order index of the swimlane vertex is contained in
 */
mxSwimlaneLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp,
\t\t\t\t\t\t\t\t\t\t\thierarchyVertices, filledVertexSet, swimlaneIndex)
{
\tif (vertex != null && allVertices != null)
\t{
\t\t// Has this vertex been seen before in any traversal
\t\t// And if the filled vertex set is populated, only 
\t\t// process vertices in that it contains
\t\tvar vertexID = mxObjectIdentity.get(vertex);
\t\t
\t\tif ((allVertices[vertexID] == null)
\t\t\t\t&& (filledVertexSet == null ? true : filledVertexSet[vertexID] != null))
\t\t{
\t\t\tif (currentComp[vertexID] == null)
\t\t\t{
\t\t\t\tcurrentComp[vertexID] = vertex;
\t\t\t}
\t\t\tif (allVertices[vertexID] == null)
\t\t\t{
\t\t\t\tallVertices[vertexID] = vertex;
\t\t\t}

\t\t\tif (filledVertexSet !== null)
\t\t\t{
\t\t\t\tdelete filledVertexSet[vertexID];
\t\t\t}

\t\t\tvar edges = this.getEdges(vertex);
\t\t\tvar model = this.graph.model;

\t\t\tfor (var i = 0; i < edges.length; i++)
\t\t\t{
\t\t\t\tvar otherVertex = this.getVisibleTerminal(edges[i], true);
\t\t\t\tvar isSource = otherVertex == vertex;
\t\t\t\t
\t\t\t\tif (isSource)
\t\t\t\t{
\t\t\t\t\totherVertex = this.getVisibleTerminal(edges[i], false);
\t\t\t\t}

\t\t\t\tvar otherIndex = 0;
\t\t\t\t// Get the swimlane index of the other terminal
\t\t\t\tfor (otherIndex = 0; otherIndex < this.swimlanes.length; otherIndex++)
\t\t\t\t{
\t\t\t\t\tif (model.isAncestor(this.swimlanes[otherIndex], otherVertex))
\t\t\t\t\t{
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (otherIndex >= this.swimlanes.length)
\t\t\t\t{
\t\t\t\t\tcontinue;
\t\t\t\t}

\t\t\t\t// Traverse if the other vertex is within the same swimlane as
\t\t\t\t// as the current vertex, or if the swimlane index of the other
\t\t\t\t// vertex is greater than that of this vertex
\t\t\t\tif ((otherIndex > swimlaneIndex) ||
\t\t\t\t\t\t((!directed || isSource) && otherIndex == swimlaneIndex))
\t\t\t\t{
\t\t\t\t\tcurrentComp = this.traverse(otherVertex, directed, edges[i], allVertices,
\t\t\t\t\t\t\tcurrentComp, hierarchyVertices,
\t\t\t\t\t\t\tfilledVertexSet, otherIndex);
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (currentComp[vertexID] == null)
\t\t\t{
\t\t\t\t// We've seen this vertex before, but not in the current component
\t\t\t\t// This component and the one it's in need to be merged
\t\t\t\tfor (var i = 0; i < hierarchyVertices.length; i++)
\t\t\t\t{
\t\t\t\t\tvar comp = hierarchyVertices[i];

\t\t\t\t\tif (comp[vertexID] != null)
\t\t\t\t\t{
\t\t\t\t\t\tfor (var key in comp)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrentComp[key] = comp[key];
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// Remove the current component from the hierarchy set
\t\t\t\t\t\thierarchyVertices.splice(i, 1);
\t\t\t\t\t\treturn currentComp;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn currentComp;
};

/**
 * Function: cycleStage
 * 
 * Executes the cycle stage using mxMinimumCycleRemover.
 */
mxSwimlaneLayout.prototype.cycleStage = function(parent)
{
\tvar cycleStage = new mxSwimlaneOrdering(this);
\tcycleStage.execute(parent);
};

/**
 * Function: layeringStage
 * 
 * Implements first stage of a Sugiyama layout.
 */
mxSwimlaneLayout.prototype.layeringStage = function()
{
\tthis.model.initialRank();
\tthis.model.fixRanks();
};

/**
 * Function: crossingStage
 * 
 * Executes the crossing stage using mxMedianHybridCrossingReduction.
 */
mxSwimlaneLayout.prototype.crossingStage = function(parent)
{
\tvar crossingStage = new mxMedianHybridCrossingReduction(this);
\tcrossingStage.execute(parent);
};

/**
 * Function: placementStage
 * 
 * Executes the placement stage using mxCoordinateAssignment.
 */
mxSwimlaneLayout.prototype.placementStage = function(initialX, parent)
{
\tvar placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing,
\t\t\tthis.interRankCellSpacing, this.orientation, initialX,
\t\t\tthis.parallelEdgeSpacing);
\tplacementStage.fineTuning = this.fineTuning;
\tplacementStage.execute(parent);
\t
\treturn placementStage.limitX + this.interHierarchySpacing;
};
/**
 * Copyright (c) 2006-2018, JGraph Ltd
 * Copyright (c) 2006-2018, Gaudenz Alder
 */
/**
 * Class: mxGraphModel
 * 
 * Extends <mxEventSource> to implement a graph model. The graph model acts as
 * a wrapper around the cells which are in charge of storing the actual graph
 * datastructure. The model acts as a transactional wrapper with event
 * notification for all changes, whereas the cells contain the atomic
 * operations for updating the actual datastructure.
 * 
 * Layers:
 * 
 * The cell hierarchy in the model must have a top-level root cell which
 * contains the layers (typically one default layer), which in turn contain the
 * top-level cells of the layers. This means each cell is contained in a layer.
 * If no layers are required, then all new cells should be added to the default
 * layer.
 * 
 * Layers are useful for hiding and showing groups of cells, or for placing
 * groups of cells on top of other cells in the display. To identify a layer,
 * the <isLayer> function is used. It returns true if the parent of the given
 * cell is the root of the model.
 * 
 * Events:
 * 
 * See events section for more details. There is a new set of events for
 * tracking transactional changes as they happen. The events are called
 * startEdit for the initial beginUpdate, executed for each executed change
 * and endEdit for the terminal endUpdate. The executed event contains a
 * property called change which represents the change after execution.
 * 
 * Encoding the model:
 * 
 * To encode a graph model, use the following code:
 * 
 * (code)
 * var enc = new mxCodec();
 * var node = enc.encode(graph.getModel());
 * (end)
 * 
 * This will create an XML node that contains all the model information.
 * 
 * Encoding and decoding changes:
 * 
 * For the encoding of changes, a graph model listener is required that encodes
 * each change from the given array of changes.
 * 
 * (code)
 * model.addListener(mxEvent.CHANGE, function(sender, evt)
 * {
 *   var changes = evt.getProperty('edit').changes;
 *   var nodes = [];
 *   var codec = new mxCodec();
 * 
 *   for (var i = 0; i < changes.length; i++)
 *   {
 *     nodes.push(codec.encode(changes[i]));
 *   }
 *   // do something with the nodes
 * });
 * (end)
 * 
 * For the decoding and execution of changes, the codec needs a lookup function
 * that allows it to resolve cell IDs as follows:
 * 
 * (code)
 * var codec = new mxCodec();
 * codec.lookup = function(id)
 * {
 *   return model.getCell(id);
 * }
 * (end)
 * 
 * For each encoded change (represented by a node), the following code can be
 * used to carry out the decoding and create a change object.
 * 
 * (code)
 * var changes = [];
 * var change = codec.decode(node);
 * change.model = model;
 * change.execute();
 * changes.push(change);
 * (end)
 * 
 * The changes can then be dispatched using the model as follows.
 * 
 * (code)
 * var edit = new mxUndoableEdit(model, false);
 * edit.changes = changes;
 * 
 * edit.notify = function()
 * {
 *   edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
 *   \t'edit', edit, 'changes', edit.changes));
 *   edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
 *   \t'edit', edit, 'changes', edit.changes));
 * }
 * 
 * model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
 * model.fireEvent(new mxEventObject(mxEvent.CHANGE,
 * \t\t'edit', edit, 'changes', changes));
 * (end)
 *
 * Event: mxEvent.CHANGE
 *
 * Fires when an undoable edit is dispatched. The <code>edit</code> property
 * contains the <mxUndoableEdit>. The <code>changes</code> property contains
 * the array of atomic changes inside the undoable edit. The changes property
 * is <strong>deprecated</strong>, please use edit.changes instead.
 *
 * Example:
 * 
 * For finding newly inserted cells, the following code can be used:
 * 
 * (code)
 * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
 * {
 *   var changes = evt.getProperty('edit').changes;
 * 
 *   for (var i = 0; i < changes.length; i++)
 *   {
 *     var change = changes[i];
 *     
 *     if (change instanceof mxChildChange &&
 *       change.change.previous == null)
 *     {
 *       graph.startEditingAtCell(change.child);
 *       break;
 *     }
 *   }
 * });
 * (end)
 * 
 * 
 * Event: mxEvent.NOTIFY
 *
 * Same as <mxEvent.CHANGE>, this event can be used for classes that need to
 * implement a sync mechanism between this model and, say, a remote model. In
 * such a setup, only local changes should trigger a notify event and all
 * changes should trigger a change event.
 * 
 * Event: mxEvent.EXECUTE
 * 
 * Fires between begin- and endUpdate and after an atomic change was executed
 * in the model. The <code>change</code> property contains the atomic change
 * that was executed.
 * 
 * Event: mxEvent.EXECUTED
 * 
 * Fires between START_EDIT and END_EDIT after an atomic change was executed.
 * The <code>change</code> property contains the change that was executed.
 *
 * Event: mxEvent.BEGIN_UPDATE
 *
 * Fires after the <updateLevel> was incremented in <beginUpdate>. This event
 * contains no properties.
 * 
 * Event: mxEvent.START_EDIT
 *
 * Fires after the <updateLevel> was changed from 0 to 1. This event
 * contains no properties.
 * 
 * Event: mxEvent.END_UPDATE
 * 
 * Fires after the <updateLevel> was decreased in <endUpdate> but before any
 * notification or change dispatching. The <code>edit</code> property contains
 * the <currentEdit>.
 * 
 * Event: mxEvent.END_EDIT
 *
 * Fires after the <updateLevel> was changed from 1 to 0. This event
 * contains no properties.
 * 
 * Event: mxEvent.BEFORE_UNDO
 * 
 * Fires before the change is dispatched after the update level has reached 0
 * in <endUpdate>. The <code>edit</code> property contains the <curreneEdit>.
 * 
 * Event: mxEvent.UNDO
 * 
 * Fires after the change was dispatched in <endUpdate>. The <code>edit</code>
 * property contains the <currentEdit>.
 * 
 * Constructor: mxGraphModel
 * 
 * Constructs a new graph model. If no root is specified then a new root
 * <mxCell> with a default layer is created.
 * 
 * Parameters:
 * 
 * root - <mxCell> that represents the root cell.
 */
function mxGraphModel(root)
{
\tthis.currentEdit = this.createUndoableEdit();
\t
\tif (root != null)
\t{
\t\tthis.setRoot(root);
\t}
\telse
\t{
\t\tthis.clear();
\t}
};

/**
 * Extends mxEventSource.
 */
mxGraphModel.prototype = new mxEventSource();
mxGraphModel.prototype.constructor = mxGraphModel;

/**
 * Variable: root
 * 
 * Holds the root cell, which in turn contains the cells that represent the
 * layers of the diagram as child cells. That is, the actual elements of the
 * diagram are supposed to live in the third generation of cells and below.
 */
mxGraphModel.prototype.root = null;

/**
 * Variable: cells
 * 
 * Maps from Ids to cells.
 */
mxGraphModel.prototype.cells = null;

/**
 * Variable: maintainEdgeParent
 * 
 * Specifies if edges should automatically be moved into the nearest common
 * ancestor of their terminals. Default is true.
 */
mxGraphModel.prototype.maintainEdgeParent = true;

/**
 * Variable: ignoreRelativeEdgeParent
 * 
 * Specifies if relative edge parents should be ignored for finding the nearest
 * common ancestors of an edge's terminals. Default is true.
 */
mxGraphModel.prototype.ignoreRelativeEdgeParent = true;

/**
 * Variable: createIds
 * 
 * Specifies if the model should automatically create Ids for new cells.
 * Default is true.
 */
mxGraphModel.prototype.createIds = true;

/**
 * Variable: prefix
 * 
 * Defines the prefix of new Ids. Default is an empty string.
 */
mxGraphModel.prototype.prefix = '';

/**
 * Variable: postfix
 * 
 * Defines the postfix of new Ids. Default is an empty string.
 */
mxGraphModel.prototype.postfix = '';

/**
 * Variable: nextId
 * 
 * Specifies the next Id to be created. Initial value is 0.
 */
mxGraphModel.prototype.nextId = 0;

/**
 * Variable: currentEdit
 * 
 * Holds the changes for the current transaction. If the transaction is
 * closed then a new object is created for this variable using
 * <createUndoableEdit>.
 */
mxGraphModel.prototype.currentEdit = null;

/**
 * Variable: updateLevel
 * 
 * Counter for the depth of nested transactions. Each call to <beginUpdate>
 * will increment this number and each call to <endUpdate> will decrement
 * it. When the counter reaches 0, the transaction is closed and the
 * respective events are fired. Initial value is 0.
 */
mxGraphModel.prototype.updateLevel = 0;

/**
 * Variable: endingUpdate
 * 
 * True if the program flow is currently inside endUpdate.
 */
mxGraphModel.prototype.endingUpdate = false;

/**
 * Function: clear
 *
 * Sets a new root using <createRoot>.
 */
mxGraphModel.prototype.clear = function()
{
\tthis.setRoot(this.createRoot());
};

/**
 * Function: isCreateIds
 *
 * Returns <createIds>.
 */
mxGraphModel.prototype.isCreateIds = function()
{
\treturn this.createIds;
};

/**
 * Function: setCreateIds
 *
 * Sets <createIds>.
 */
mxGraphModel.prototype.setCreateIds = function(value)
{
\tthis.createIds = value;
};

/**
 * Function: createRoot
 *
 * Creates a new root cell with a default layer (child 0).
 */
mxGraphModel.prototype.createRoot = function()
{
\tvar cell = new mxCell();
\tcell.insert(new mxCell());
\t
\treturn cell;
};

/**
 * Function: getCell
 *
 * Returns the <mxCell> for the specified Id or null if no cell can be
 * found for the given Id.
 *
 * Parameters:
 * 
 * id - A string representing the Id of the cell.
 */
mxGraphModel.prototype.getCell = function(id)
{
\treturn (this.cells != null) ? this.cells[id] : null;
};

/**
 * Function: filterCells
 * 
 * Returns the cells from the given array where the given filter function
 * returns true.
 */
mxGraphModel.prototype.filterCells = function(cells, filter)
{
\tvar result = null;
\t
\tif (cells != null)
\t{
\t\tresult = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (filter(cells[i]))
\t\t\t{
\t\t\t\tresult.push(cells[i]);
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getDescendants
 * 
 * Returns all descendants of the given cell and the cell itself in an array.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose descendants should be returned.
 */
mxGraphModel.prototype.getDescendants = function(parent)
{
\treturn this.filterDescendants(null, parent);
};

/**
 * Function: filterDescendants
 * 
 * Visits all cells recursively and applies the specified filter function
 * to each cell. If the function returns true then the cell is added
 * to the resulting array. The parent and result paramters are optional.
 * If parent is not specified then the recursion starts at <root>.
 * 
 * Example:
 * The following example extracts all vertices from a given model:
 * (code)
 * var filter = function(cell)
 * {
 * \treturn model.isVertex(cell);
 * }
 * var vertices = model.filterDescendants(filter);
 * (end)
 * 
 * Parameters:
 * 
 * filter - JavaScript function that takes an <mxCell> as an argument
 * and returns a boolean.
 * parent - Optional <mxCell> that is used as the root of the recursion.
 */
mxGraphModel.prototype.filterDescendants = function(filter, parent)
{
\t// Creates a new array for storing the result
\tvar result = [];

\t// Recursion starts at the root of the model
\tparent = parent || this.getRoot();
\t
\t// Checks if the filter returns true for the cell
\t// and adds it to the result array
\tif (filter == null || filter(parent))
\t{
\t\tresult.push(parent);
\t}
\t
\t// Visits the children of the cell
\tvar childCount = this.getChildCount(parent);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = this.getChildAt(parent, i);
\t\tresult = result.concat(this.filterDescendants(filter, child));
\t}

\treturn result;
};

/**
 * Function: getRoot
 * 
 * Returns the root of the model or the topmost parent of the given cell.
 *
 * Parameters:
 * 
 * cell - Optional <mxCell> that specifies the child.
 */
mxGraphModel.prototype.getRoot = function(cell)
{
\tvar root = cell || this.root;
\t
\tif (cell != null)
\t{
\t\twhile (cell != null)
\t\t{
\t\t\troot = cell;
\t\t\tcell = this.getParent(cell);
\t\t}
\t}
\t
\treturn root;
};

/**
 * Function: setRoot
 * 
 * Sets the <root> of the model using <mxRootChange> and adds the change to
 * the current transaction. This resets all datastructures in the model and
 * is the preferred way of clearing an existing model. Returns the new
 * root.
 * 
 * Example:
 * 
 * (code)
 * var root = new mxCell();
 * root.insert(new mxCell());
 * model.setRoot(root);
 * (end)
 *
 * Parameters:
 * 
 * root - <mxCell> that specifies the new root.
 */
mxGraphModel.prototype.setRoot = function(root)
{
\tthis.execute(new mxRootChange(this, root));
\t
\treturn root;
};

/**
 * Function: rootChanged
 * 
 * Inner callback to change the root of the model and update the internal
 * datastructures, such as <cells> and <nextId>. Returns the previous root.
 *
 * Parameters:
 * 
 * root - <mxCell> that specifies the new root.
 */
mxGraphModel.prototype.rootChanged = function(root)
{
\tvar oldRoot = this.root;
\tthis.root = root;
\t
\t// Resets counters and datastructures
\tthis.nextId = 0;
\tthis.cells = null;
\tthis.cellAdded(root);
\t
\treturn oldRoot;
};

/**
 * Function: isRoot
 * 
 * Returns true if the given cell is the root of the model and a non-null
 * value.
 *
 * Parameters:
 * 
 * cell - <mxCell> that represents the possible root.
 */
mxGraphModel.prototype.isRoot = function(cell)
{
\treturn cell != null && this.root == cell;
};

/**
 * Function: isLayer
 * 
 * Returns true if <isRoot> returns true for the parent of the given cell.
 *
 * Parameters:
 * 
 * cell - <mxCell> that represents the possible layer.
 */
mxGraphModel.prototype.isLayer = function(cell)
{
\treturn this.isRoot(this.getParent(cell));
};

/**
 * Function: isAncestor
 * 
 * Returns true if the given parent is an ancestor of the given child. Note 
 * returns true if child == parent.
 *
 * Parameters:
 * 
 * parent - <mxCell> that specifies the parent.
 * child - <mxCell> that specifies the child.
 */
mxGraphModel.prototype.isAncestor = function(parent, child)
{
\twhile (child != null && child != parent)
\t{
\t\tchild = this.getParent(child);
\t}
\t
\treturn child == parent;
};

/**
 * Function: contains
 * 
 * Returns true if the model contains the given <mxCell>.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell.
 */
mxGraphModel.prototype.contains = function(cell)
{
\treturn this.isAncestor(this.root, cell);
};

/**
 * Function: getParent
 * 
 * Returns the parent of the given cell.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose parent should be returned.
 */
mxGraphModel.prototype.getParent = function(cell)
{
\treturn (cell != null) ? cell.getParent() : null;
};

/**
 * Function: add
 * 
 * Adds the specified child to the parent at the given index using
 * <mxChildChange> and adds the change to the current transaction. If no
 * index is specified then the child is appended to the parent's array of
 * children. Returns the inserted child.
 * 
 * Parameters:
 * 
 * parent - <mxCell> that specifies the parent to contain the child.
 * child - <mxCell> that specifies the child to be inserted.
 * index - Optional integer that specifies the index of the child.
 */
mxGraphModel.prototype.add = function(parent, child, index)
{
\tif (child != parent && parent != null && child != null)
\t{\t
\t\t// Appends the child if no index was specified
\t\tif (index == null)
\t\t{
\t\t\tindex = this.getChildCount(parent);
\t\t}
\t\t
\t\tvar parentChanged = parent != this.getParent(child);
\t\tthis.execute(new mxChildChange(this, parent, child, index));

\t\t// Maintains the edges parents by moving the edges
\t\t// into the nearest common ancestor of its terminals
\t\tif (this.maintainEdgeParent && parentChanged)
\t\t{
\t\t\tthis.updateEdgeParents(child);
\t\t}
\t}
\t
\treturn child;
};

/**
 * Function: cellAdded
 * 
 * Inner callback to update <cells> when a cell has been added. This
 * implementation resolves collisions by creating new Ids. To change the
 * ID of a cell after it was inserted into the model, use the following
 * code:
 * 
 * (code
 * delete model.cells[cell.getId()];
 * cell.setId(newId);
 * model.cells[cell.getId()] = cell;
 * (end)
 *
 * If the change of the ID should be part of the command history, then the
 * cell should be removed from the model and a clone with the new ID should
 * be reinserted into the model instead.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell that has been added.
 */
mxGraphModel.prototype.cellAdded = function(cell)
{
\tif (cell != null)
\t{
\t\t// Creates an Id for the cell if not Id exists
\t\tif (cell.getId() == null && this.createIds)
\t\t{
\t\t\tcell.setId(this.createId(cell));
\t\t}
\t\t
\t\tif (cell.getId() != null)
\t\t{
\t\t\tvar collision = this.getCell(cell.getId());
\t\t\t
\t\t\tif (collision != cell)
\t\t\t{\t
\t\t\t\t// Creates new Id for the cell
\t\t\t\t// as long as there is a collision
\t\t\t\twhile (collision != null)
\t\t\t\t{
\t\t\t\t\tcell.setId(this.createId(cell));
\t\t\t\t\tcollision = this.getCell(cell.getId());
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Lazily creates the cells dictionary
\t\t\t\tif (this.cells == null)
\t\t\t\t{
\t\t\t\t\tthis.cells = new Object();
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.cells[cell.getId()] = cell;
\t\t\t}
\t\t}
\t\t
\t\t// Makes sure IDs of deleted cells are not reused
\t\tif (mxUtils.isNumeric(cell.getId()))
\t\t{
\t\t\tthis.nextId = Math.max(this.nextId, cell.getId());
\t\t}
\t\t
\t\t// Recursively processes child cells
\t\tvar childCount = this.getChildCount(cell);
\t\t
\t\tfor (var i=0; i<childCount; i++)
\t\t{
\t\t\tthis.cellAdded(this.getChildAt(cell, i));
\t\t}
\t}
};

/**
 * Function: createId
 * 
 * Hook method to create an Id for the specified cell. This implementation
 * concatenates <prefix>, id and <postfix> to create the Id and increments
 * <nextId>. The cell is ignored by this implementation, but can be used in
 * overridden methods to prefix the Ids with eg. the cell type.
 *
 * Parameters:
 *
 * cell - <mxCell> to create the Id for.
 */
mxGraphModel.prototype.createId = function(cell)
{
\tvar id = this.nextId;
\tthis.nextId++;
\t
\treturn this.prefix + id + this.postfix;
};

/**
 * Function: updateEdgeParents
 * 
 * Updates the parent for all edges that are connected to cell or one of
 * its descendants using <updateEdgeParent>.
 */
mxGraphModel.prototype.updateEdgeParents = function(cell, root)
{
\t// Gets the topmost node of the hierarchy
\troot = root || this.getRoot(cell);
\t
\t// Updates edges on children first
\tvar childCount = this.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = this.getChildAt(cell, i);
\t\tthis.updateEdgeParents(child, root);
\t}
\t
\t// Updates the parents of all connected edges
\tvar edgeCount = this.getEdgeCount(cell);
\tvar edges = [];

\tfor (var i = 0; i < edgeCount; i++)
\t{
\t\tedges.push(this.getEdgeAt(cell, i));
\t}
\t
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar edge = edges[i];
\t\t
\t\t// Updates edge parent if edge and child have
\t\t// a common root node (does not need to be the
\t\t// model root node)
\t\tif (this.isAncestor(root, edge))
\t\t{
\t\t\tthis.updateEdgeParent(edge, root);
\t\t}
\t}
};

/**
 * Function: updateEdgeParent
 *
 * Inner callback to update the parent of the specified <mxCell> to the
 * nearest-common-ancestor of its two terminals.
 *
 * Parameters:
 * 
 * edge - <mxCell> that specifies the edge.
 * root - <mxCell> that represents the current root of the model.
 */
mxGraphModel.prototype.updateEdgeParent = function(edge, root)
{
\tvar source = this.getTerminal(edge, true);
\tvar target = this.getTerminal(edge, false);
\tvar cell = null;
\t
\t// Uses the first non-relative descendants of the source terminal
\twhile (source != null && !this.isEdge(source) &&
\t\tsource.geometry != null && source.geometry.relative)
\t{
\t\tsource = this.getParent(source);
\t}
\t
\t// Uses the first non-relative descendants of the target terminal
\twhile (target != null && this.ignoreRelativeEdgeParent &&
\t\t!this.isEdge(target) && target.geometry != null && 
\t\ttarget.geometry.relative)
\t{
\t\ttarget = this.getParent(target);
\t}
\t
\tif (this.isAncestor(root, source) && this.isAncestor(root, target))
\t{
\t\tif (source == target)
\t\t{
\t\t\tcell = this.getParent(source);
\t\t}
\t\telse
\t\t{
\t\t\tcell = this.getNearestCommonAncestor(source, target);
\t\t}

\t\tif (cell != null && (this.getParent(cell) != this.root ||
\t\t\tthis.isAncestor(cell, edge)) && this.getParent(edge) != cell)
\t\t{
\t\t\tvar geo = this.getGeometry(edge);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tvar origin1 = this.getOrigin(this.getParent(edge));
\t\t\t\tvar origin2 = this.getOrigin(cell);
\t\t\t\t
\t\t\t\tvar dx = origin2.x - origin1.x;
\t\t\t\tvar dy = origin2.y - origin1.y;
\t\t\t\t
\t\t\t\tgeo = geo.clone();
\t\t\t\tgeo.translate(-dx, -dy);
\t\t\t\tthis.setGeometry(edge, geo);
\t\t\t}

\t\t\tthis.add(cell, edge, this.getChildCount(cell));
\t\t}
\t}
};

/**
 * Function: getOrigin
 * 
 * Returns the absolute, accumulated origin for the children inside the
 * given parent as an <mxPoint>.
 */
mxGraphModel.prototype.getOrigin = function(cell)
{
\tvar result = null;
\t
\tif (cell != null)
\t{
\t\tresult = this.getOrigin(this.getParent(cell));
\t\t
\t\tif (!this.isEdge(cell))
\t\t{
\t\t\tvar geo = this.getGeometry(cell);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tresult.x += geo.x;
\t\t\t\tresult.y += geo.y;
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tresult = new mxPoint();
\t}
\t
\treturn result;
};

/**
 * Function: getNearestCommonAncestor
 * 
 * Returns the nearest common ancestor for the specified cells.
 *
 * Parameters:
 * 
 * cell1 - <mxCell> that specifies the first cell in the tree.
 * cell2 - <mxCell> that specifies the second cell in the tree.
 */
mxGraphModel.prototype.getNearestCommonAncestor = function(cell1, cell2)
{
\tif (cell1 != null && cell2 != null)
\t{\t\t
\t\t// Creates the cell path for the second cell
\t\tvar path = mxCellPath.create(cell2);

\t\tif (path != null && path.length > 0)
\t\t{
\t\t\t// Bubbles through the ancestors of the first
\t\t\t// cell to find the nearest common ancestor.
\t\t\tvar cell = cell1;
\t\t\tvar current = mxCellPath.create(cell);
\t\t\t
\t\t\t// Inverts arguments
\t\t\tif (path.length < current.length)
\t\t\t{
\t\t\t\tcell = cell2;
\t\t\t\tvar tmp = current;
\t\t\t\tcurrent = path;
\t\t\t\tpath = tmp;
\t\t\t}
\t\t\t
\t\t\twhile (cell != null)
\t\t\t{
\t\t\t\tvar parent = this.getParent(cell);
\t\t\t\t
\t\t\t\t// Checks if the cell path is equal to the beginning of the given cell path
\t\t\t\tif (path.indexOf(current + mxCellPath.PATH_SEPARATOR) == 0 && parent != null)
\t\t\t\t{
\t\t\t\t\treturn cell;
\t\t\t\t}
\t\t\t\t
\t\t\t\tcurrent = mxCellPath.getParentPath(current);
\t\t\t\tcell = parent;
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: remove
 * 
 * Removes the specified cell from the model using <mxChildChange> and adds
 * the change to the current transaction. This operation will remove the
 * cell and all of its children from the model. Returns the removed cell.
 *
 * Parameters:
 * 
 * cell - <mxCell> that should be removed.
 */
mxGraphModel.prototype.remove = function(cell)
{
\tif (cell == this.root)
\t{
\t\tthis.setRoot(null);
\t}
\telse if (this.getParent(cell) != null)
\t{
\t\tthis.execute(new mxChildChange(this, null, cell));
\t}
\t
\treturn cell;
};

/**
 * Function: cellRemoved
 * 
 * Inner callback to update <cells> when a cell has been removed.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell that has been removed.
 */
mxGraphModel.prototype.cellRemoved = function(cell)
{
\tif (cell != null && this.cells != null)
\t{
\t\t// Recursively processes child cells
\t\tvar childCount = this.getChildCount(cell);
\t\t
\t\tfor (var i = childCount - 1; i >= 0; i--)
\t\t{
\t\t\tthis.cellRemoved(this.getChildAt(cell, i));
\t\t}
\t\t
\t\t// Removes the dictionary entry for the cell
\t\tif (this.cells != null && cell.getId() != null)
\t\t{
\t\t\tdelete this.cells[cell.getId()];
\t\t}
\t}
};

/**
 * Function: parentForCellChanged
 * 
 * Inner callback to update the parent of a cell using <mxCell.insert>
 * on the parent and return the previous parent.
 *
 * Parameters:
 * 
 * cell - <mxCell> to update the parent for.
 * parent - <mxCell> that specifies the new parent of the cell.
 * index - Optional integer that defines the index of the child
 * in the parent's child array.
 */
mxGraphModel.prototype.parentForCellChanged = function(cell, parent, index)
{
\tvar previous = this.getParent(cell);
\t
\tif (parent != null)
\t{
\t\tif (parent != previous || previous.getIndex(cell) != index)
\t\t{
\t\t\tparent.insert(cell, index);
\t\t}
\t}
\telse if (previous != null)
\t{
\t\tvar oldIndex = previous.getIndex(cell);
\t\tprevious.remove(oldIndex);
\t}
\t
\t// Adds or removes the cell from the model
\tvar par = this.contains(parent);
\tvar pre = this.contains(previous);
\t
\tif (par && !pre)
\t{
\t\tthis.cellAdded(cell);
\t}
\telse if (pre && !par)
\t{
\t\tthis.cellRemoved(cell);
\t}
\t
\treturn previous;
};

/**
 * Function: getChildCount
 *
 * Returns the number of children in the given cell.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose number of children should be returned.
 */
mxGraphModel.prototype.getChildCount = function(cell)
{
\treturn (cell != null) ? cell.getChildCount() : 0;
};

/**
 * Function: getChildAt
 *
 * Returns the child of the given <mxCell> at the given index.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the parent.
 * index - Integer that specifies the index of the child to be returned.
 */
mxGraphModel.prototype.getChildAt = function(cell, index)
{
\treturn (cell != null) ? cell.getChildAt(index) : null;
};

/**
 * Function: getChildren
 * 
 * Returns all children of the given <mxCell> as an array of <mxCells>. The
 * return value should be only be read.
 *
 * Parameters:
 * 
 * cell - <mxCell> the represents the parent.
 */
mxGraphModel.prototype.getChildren = function(cell)
{
\treturn (cell != null) ? cell.children : null;
};
\t
/**
 * Function: getChildVertices
 * 
 * Returns the child vertices of the given parent.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose child vertices should be returned.
 */
mxGraphModel.prototype.getChildVertices = function(parent)
{
\treturn this.getChildCells(parent, true, false);
};
\t\t
/**
 * Function: getChildEdges
 * 
 * Returns the child edges of the given parent.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose child edges should be returned.
 */
mxGraphModel.prototype.getChildEdges = function(parent)
{
\treturn this.getChildCells(parent, false, true);
};

/**
 * Function: getChildCells
 * 
 * Returns the children of the given cell that are vertices and/or edges
 * depending on the arguments.
 *
 * Parameters:
 * 
 * cell - <mxCell> the represents the parent.
 * vertices - Boolean indicating if child vertices should be returned.
 * Default is false.
 * edges - Boolean indicating if child edges should be returned.
 * Default is false.
 */
mxGraphModel.prototype.getChildCells = function(parent, vertices, edges)
{
\tvertices = (vertices != null) ? vertices : false;
\tedges = (edges != null) ? edges : false;
\t
\tvar childCount = this.getChildCount(parent);
\tvar result = [];

\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = this.getChildAt(parent, i);

\t\tif ((!edges && !vertices) || (edges && this.isEdge(child)) ||
\t\t\t(vertices && this.isVertex(child)))
\t\t{
\t\t\tresult.push(child);
\t\t}
\t}

\treturn result;
};
\t\t
/**
 * Function: getTerminal
 * 
 * Returns the source or target <mxCell> of the given edge depending on the
 * value of the boolean parameter.
 *
 * Parameters:
 * 
 * edge - <mxCell> that specifies the edge.
 * isSource - Boolean indicating which end of the edge should be returned.
 */
mxGraphModel.prototype.getTerminal = function(edge, isSource)
{
\treturn (edge != null) ? edge.getTerminal(isSource) : null;
};

/**
 * Function: setTerminal
 * 
 * Sets the source or target terminal of the given <mxCell> using
 * <mxTerminalChange> and adds the change to the current transaction.
 * This implementation updates the parent of the edge using <updateEdgeParent>
 * if required.
 *
 * Parameters:
 * 
 * edge - <mxCell> that specifies the edge.
 * terminal - <mxCell> that specifies the new terminal.
 * isSource - Boolean indicating if the terminal is the new source or
 * target terminal of the edge.
 */
mxGraphModel.prototype.setTerminal = function(edge, terminal, isSource)
{
\tvar terminalChanged = terminal != this.getTerminal(edge, isSource);
\tthis.execute(new mxTerminalChange(this, edge, terminal, isSource));
\t
\tif (this.maintainEdgeParent && terminalChanged)
\t{
\t\tthis.updateEdgeParent(edge, this.getRoot());
\t}
\t
\treturn terminal;
};
\t
/**
 * Function: setTerminals
 * 
 * Sets the source and target <mxCell> of the given <mxCell> in a single
 * transaction using <setTerminal> for each end of the edge.
 *
 * Parameters:
 * 
 * edge - <mxCell> that specifies the edge.
 * source - <mxCell> that specifies the new source terminal.
 * target - <mxCell> that specifies the new target terminal.
 */
mxGraphModel.prototype.setTerminals = function(edge, source, target)
{
\tthis.beginUpdate();
\ttry
\t{
\t\tthis.setTerminal(edge, source, true);
\t\tthis.setTerminal(edge, target, false);
\t}
\tfinally
\t{
\t\tthis.endUpdate();
\t}
};

/**
 * Function: terminalForCellChanged
 * 
 * Inner helper function to update the terminal of the edge using
 * <mxCell.insertEdge> and return the previous terminal.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that specifies the edge to be updated.
 * terminal - <mxCell> that specifies the new terminal.
 * isSource - Boolean indicating if the terminal is the new source or
 * target terminal of the edge.
 */
mxGraphModel.prototype.terminalForCellChanged = function(edge, terminal, isSource)
{
\tvar previous = this.getTerminal(edge, isSource);
\t
\tif (terminal != null)
\t{
\t\tterminal.insertEdge(edge, isSource);
\t}
\telse if (previous != null)
\t{
\t\tprevious.removeEdge(edge, isSource);
\t}
\t
\treturn previous;
};

/**
 * Function: getEdgeCount
 * 
 * Returns the number of distinct edges connected to the given cell.
 *
 * Parameters:
 * 
 * cell - <mxCell> that represents the vertex.
 */
mxGraphModel.prototype.getEdgeCount = function(cell)
{
\treturn (cell != null) ? cell.getEdgeCount() : 0;
};

/**
 * Function: getEdgeAt
 * 
 * Returns the edge of cell at the given index.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the vertex.
 * index - Integer that specifies the index of the edge
 * to return.
 */
mxGraphModel.prototype.getEdgeAt = function(cell, index)
{
\treturn (cell != null) ? cell.getEdgeAt(index) : null;
};
\t
/**
 * Function: getDirectedEdgeCount
 * 
 * Returns the number of incoming or outgoing edges, ignoring the given
 * edge.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose edge count should be returned.
 * outgoing - Boolean that specifies if the number of outgoing or
 * incoming edges should be returned.
 * ignoredEdge - <mxCell> that represents an edge to be ignored.
 */
mxGraphModel.prototype.getDirectedEdgeCount = function(cell, outgoing, ignoredEdge)
{
\tvar count = 0;
\tvar edgeCount = this.getEdgeCount(cell);

\tfor (var i = 0; i < edgeCount; i++)
\t{
\t\tvar edge = this.getEdgeAt(cell, i);

\t\tif (edge != ignoredEdge && this.getTerminal(edge, outgoing) == cell)
\t\t{
\t\t\tcount++;
\t\t}
\t}

\treturn count;
};

/**
 * Function: getConnections
 * 
 * Returns all edges of the given cell without loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose edges should be returned.
 * 
 */
mxGraphModel.prototype.getConnections = function(cell)
{
\treturn this.getEdges(cell, true, true, false);
};

/**
 * Function: getIncomingEdges
 * 
 * Returns the incoming edges of the given cell without loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose incoming edges should be returned.
 * 
 */
mxGraphModel.prototype.getIncomingEdges = function(cell)
{
\treturn this.getEdges(cell, true, false, false);
};

/**
 * Function: getOutgoingEdges
 * 
 * Returns the outgoing edges of the given cell without loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose outgoing edges should be returned.
 * 
 */
mxGraphModel.prototype.getOutgoingEdges = function(cell)
{
\treturn this.getEdges(cell, false, true, false);
};

/**
 * Function: getEdges
 * 
 * Returns all distinct edges connected to this cell as a new array of
 * <mxCells>. If at least one of incoming or outgoing is true, then loops
 * are ignored, otherwise if both are false, then all edges connected to
 * the given cell are returned including loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell.
 * incoming - Optional boolean that specifies if incoming edges should be
 * returned. Default is true.
 * outgoing - Optional boolean that specifies if outgoing edges should be
 * returned. Default is true.
 * includeLoops - Optional boolean that specifies if loops should be returned.
 * Default is true. 
 */
mxGraphModel.prototype.getEdges = function(cell, incoming, outgoing, includeLoops)
{
\tincoming = (incoming != null) ? incoming : true;
\toutgoing = (outgoing != null) ? outgoing : true;
\tincludeLoops = (includeLoops != null) ? includeLoops : true;
\t
\tvar edgeCount = this.getEdgeCount(cell);
\tvar result = [];

\tfor (var i = 0; i < edgeCount; i++)
\t{
\t\tvar edge = this.getEdgeAt(cell, i);
\t\tvar source = this.getTerminal(edge, true);
\t\tvar target = this.getTerminal(edge, false);

\t\tif ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) ||
\t\t\t(outgoing && source == cell))))
\t\t{
\t\t\tresult.push(edge);
\t\t}
\t}

\treturn result;
};

/**
 * Function: getEdgesBetween
 * 
 * Returns all edges between the given source and target pair. If directed
 * is true, then only edges from the source to the target are returned,
 * otherwise, all edges between the two cells are returned.
 * 
 * Parameters:
 * 
 * source - <mxCell> that defines the source terminal of the edge to be
 * returned.
 * target - <mxCell> that defines the target terminal of the edge to be
 * returned.
 * directed - Optional boolean that specifies if the direction of the
 * edge should be taken into account. Default is false.
 */
mxGraphModel.prototype.getEdgesBetween = function(source, target, directed)
{
\tdirected = (directed != null) ? directed : false;
\t
\tvar tmp1 = this.getEdgeCount(source);
\tvar tmp2 = this.getEdgeCount(target);
\t
\t// Assumes the source has less connected edges
\tvar terminal = source;
\tvar edgeCount = tmp1;
\t
\t// Uses the smaller array of connected edges
\t// for searching the edge
\tif (tmp2 < tmp1)
\t{
\t\tedgeCount = tmp2;
\t\tterminal = target;
\t}
\t
\tvar result = [];
\t
\t// Checks if the edge is connected to the correct
\t// cell and returns the first match
\tfor (var i = 0; i < edgeCount; i++)
\t{
\t\tvar edge = this.getEdgeAt(terminal, i);
\t\tvar src = this.getTerminal(edge, true);
\t\tvar trg = this.getTerminal(edge, false);
\t\tvar directedMatch = (src == source) && (trg == target);
\t\tvar oppositeMatch = (trg == source) && (src == target);

\t\tif (directedMatch || (!directed && oppositeMatch))
\t\t{
\t\t\tresult.push(edge);
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getOpposites
 * 
 * Returns all opposite vertices wrt terminal for the given edges, only
 * returning sources and/or targets as specified. The result is returned
 * as an array of <mxCells>.
 * 
 * Parameters:
 * 
 * edges - Array of <mxCells> that contain the edges to be examined.
 * terminal - <mxCell> that specifies the known end of the edges.
 * sources - Boolean that specifies if source terminals should be contained
 * in the result. Default is true.
 * targets - Boolean that specifies if target terminals should be contained
 * in the result. Default is true.
 */
mxGraphModel.prototype.getOpposites = function(edges, terminal, sources, targets)
{
\tsources = (sources != null) ? sources : true;
\ttargets = (targets != null) ? targets : true;
\t
\tvar terminals = [];
\t
\tif (edges != null)
\t{
\t\tfor (var i = 0; i < edges.length; i++)
\t\t{
\t\t\tvar source = this.getTerminal(edges[i], true);
\t\t\tvar target = this.getTerminal(edges[i], false);
\t\t\t
\t\t\t// Checks if the terminal is the source of
\t\t\t// the edge and if the target should be
\t\t\t// stored in the result
\t\t\tif (source == terminal && target != null && target != terminal && targets)
\t\t\t{
\t\t\t\tterminals.push(target);
\t\t\t}
\t\t\t
\t\t\t// Checks if the terminal is the taget of
\t\t\t// the edge and if the source should be
\t\t\t// stored in the result
\t\t\telse if (target == terminal && source != null && source != terminal && sources)
\t\t\t{
\t\t\t\tterminals.push(source);
\t\t\t}
\t\t}
\t}
\t
\treturn terminals;
};

/**
 * Function: getTopmostCells
 * 
 * Returns the topmost cells of the hierarchy in an array that contains no
 * descendants for each <mxCell> that it contains. Duplicates should be
 * removed in the cells array to improve performance.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose topmost ancestors should be returned.
 */
mxGraphModel.prototype.getTopmostCells = function(cells)
{
\tvar dict = new mxDictionary();
\tvar tmp = [];
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tdict.put(cells[i], true);
\t}
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tvar cell = cells[i];
\t\tvar topmost = true;
\t\tvar parent = this.getParent(cell);
\t\t
\t\twhile (parent != null)
\t\t{
\t\t\tif (dict.get(parent))
\t\t\t{
\t\t\t\ttopmost = false;
\t\t\t\tbreak;
\t\t\t}
\t\t\t
\t\t\tparent = this.getParent(parent);
\t\t}
\t\t
\t\tif (topmost)
\t\t{
\t\t\ttmp.push(cell);
\t\t}
\t}
\t
\treturn tmp;
};

/**
 * Function: isVertex
 * 
 * Returns true if the given cell is a vertex.
 *
 * Parameters:
 * 
 * cell - <mxCell> that represents the possible vertex.
 */
mxGraphModel.prototype.isVertex = function(cell)
{
\treturn (cell != null) ? cell.isVertex() : false;
};

/**
 * Function: isEdge
 * 
 * Returns true if the given cell is an edge.
 *
 * Parameters:
 * 
 * cell - <mxCell> that represents the possible edge.
 */
mxGraphModel.prototype.isEdge = function(cell)
{
\treturn (cell != null) ? cell.isEdge() : false;
};

/**
 * Function: isConnectable
 * 
 * Returns true if the given <mxCell> is connectable. If <edgesConnectable>
 * is false, then this function returns false for all edges else it returns
 * the return value of <mxCell.isConnectable>.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose connectable state should be returned.
 */
mxGraphModel.prototype.isConnectable = function(cell)
{
\treturn (cell != null) ? cell.isConnectable() : false;
};

/**
 * Function: getValue
 * 
 * Returns the user object of the given <mxCell> using <mxCell.getValue>.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose user object should be returned.
 */
mxGraphModel.prototype.getValue = function(cell)
{
\treturn (cell != null) ? cell.getValue() : null;
};

/**
 * Function: setValue
 * 
 * Sets the user object of then given <mxCell> using <mxValueChange>
 * and adds the change to the current transaction.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose user object should be changed.
 * value - Object that defines the new user object.
 */
mxGraphModel.prototype.setValue = function(cell, value)
{
\tthis.execute(new mxValueChange(this, cell, value));
\t
\treturn value;
};

/**
 * Function: valueForCellChanged
 * 
 * Inner callback to update the user object of the given <mxCell>
 * using <mxCell.valueChanged> and return the previous value,
 * that is, the return value of <mxCell.valueChanged>.
 * 
 * To change a specific attribute in an XML node, the following code can be
 * used.
 * 
 * (code)
 * graph.getModel().valueForCellChanged = function(cell, value)
 * {
 *   var previous = cell.value.getAttribute('label');
 *   cell.value.setAttribute('label', value);
 *   
 *   return previous;
 * };
 * (end) 
 */
mxGraphModel.prototype.valueForCellChanged = function(cell, value)
{
\treturn cell.valueChanged(value);
};

/**
 * Function: getGeometry
 * 
 * Returns the <mxGeometry> of the given <mxCell>.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose geometry should be returned.
 */
mxGraphModel.prototype.getGeometry = function(cell)
{
\treturn (cell != null) ? cell.getGeometry() : null;
};

/**
 * Function: setGeometry
 * 
 * Sets the <mxGeometry> of the given <mxCell>. The actual update
 * of the cell is carried out in <geometryForCellChanged>. The
 * <mxGeometryChange> action is used to encapsulate the change.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose geometry should be changed.
 * geometry - <mxGeometry> that defines the new geometry.
 */
mxGraphModel.prototype.setGeometry = function(cell, geometry)
{
\tif (geometry != this.getGeometry(cell))
\t{
\t\tthis.execute(new mxGeometryChange(this, cell, geometry));
\t}
\t
\treturn geometry;
};

/**
 * Function: geometryForCellChanged
 * 
 * Inner callback to update the <mxGeometry> of the given <mxCell> using
 * <mxCell.setGeometry> and return the previous <mxGeometry>.
 */
mxGraphModel.prototype.geometryForCellChanged = function(cell, geometry)
{
\tvar previous = this.getGeometry(cell);
\tcell.setGeometry(geometry);
\t
\treturn previous;
};

/**
 * Function: getStyle
 * 
 * Returns the style of the given <mxCell>.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose style should be returned.
 */
mxGraphModel.prototype.getStyle = function(cell)
{
\treturn (cell != null) ? cell.getStyle() : null;
};

/**
 * Function: setStyle
 * 
 * Sets the style of the given <mxCell> using <mxStyleChange> and
 * adds the change to the current transaction.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose style should be changed.
 * style - String of the form [stylename;|key=value;] to specify
 * the new cell style.
 */
mxGraphModel.prototype.setStyle = function(cell, style)
{
\tif (style != this.getStyle(cell))
\t{
\t\tthis.execute(new mxStyleChange(this, cell, style));
\t}
\t
\treturn style;
};

/**
 * Function: styleForCellChanged
 * 
 * Inner callback to update the style of the given <mxCell>
 * using <mxCell.setStyle> and return the previous style.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell to be updated.
 * style - String of the form [stylename;|key=value;] to specify
 * the new cell style.
 */
mxGraphModel.prototype.styleForCellChanged = function(cell, style)
{
\tvar previous = this.getStyle(cell);
\tcell.setStyle(style);
\t
\treturn previous;
};

/**
 * Function: isCollapsed
 * 
 * Returns true if the given <mxCell> is collapsed.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose collapsed state should be returned.
 */
mxGraphModel.prototype.isCollapsed = function(cell)
{
\treturn (cell != null) ? cell.isCollapsed() : false;
};

/**
 * Function: setCollapsed
 * 
 * Sets the collapsed state of the given <mxCell> using <mxCollapseChange>
 * and adds the change to the current transaction.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose collapsed state should be changed.
 * collapsed - Boolean that specifies the new collpased state.
 */
mxGraphModel.prototype.setCollapsed = function(cell, collapsed)
{
\tif (collapsed != this.isCollapsed(cell))
\t{
\t\tthis.execute(new mxCollapseChange(this, cell, collapsed));
\t}
\t
\treturn collapsed;
};
\t
/**
 * Function: collapsedStateForCellChanged
 *
 * Inner callback to update the collapsed state of the
 * given <mxCell> using <mxCell.setCollapsed> and return
 * the previous collapsed state.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell to be updated.
 * collapsed - Boolean that specifies the new collpased state.
 */
mxGraphModel.prototype.collapsedStateForCellChanged = function(cell, collapsed)
{
\tvar previous = this.isCollapsed(cell);
\tcell.setCollapsed(collapsed);
\t
\treturn previous;
};

/**
 * Function: isVisible
 * 
 * Returns true if the given <mxCell> is visible.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose visible state should be returned.
 */
mxGraphModel.prototype.isVisible = function(cell)
{
\treturn (cell != null) ? cell.isVisible() : false;
};

/**
 * Function: setVisible
 * 
 * Sets the visible state of the given <mxCell> using <mxVisibleChange> and
 * adds the change to the current transaction.
 *
 * Parameters:
 * 
 * cell - <mxCell> whose visible state should be changed.
 * visible - Boolean that specifies the new visible state.
 */
mxGraphModel.prototype.setVisible = function(cell, visible)
{
\tif (visible != this.isVisible(cell))
\t{
\t\tthis.execute(new mxVisibleChange(this, cell, visible));
\t}
\t
\treturn visible;
};
\t
/**
 * Function: visibleStateForCellChanged
 *
 * Inner callback to update the visible state of the
 * given <mxCell> using <mxCell.setCollapsed> and return
 * the previous visible state.
 *
 * Parameters:
 * 
 * cell - <mxCell> that specifies the cell to be updated.
 * visible - Boolean that specifies the new visible state.
 */
mxGraphModel.prototype.visibleStateForCellChanged = function(cell, visible)
{
\tvar previous = this.isVisible(cell);
\tcell.setVisible(visible);
\t
\treturn previous;
};

/**
 * Function: execute
 * 
 * Executes the given edit and fires events if required. The edit object
 * requires an execute function which is invoked. The edit is added to the
 * <currentEdit> between <beginUpdate> and <endUpdate> calls, so that
 * events will be fired if this execute is an individual transaction, that
 * is, if no previous <beginUpdate> calls have been made without calling
 * <endUpdate>. This implementation fires an <execute> event before
 * executing the given change.
 * 
 * Parameters:
 * 
 * change - Object that described the change.
 */
mxGraphModel.prototype.execute = function(change)
{
\tchange.execute();
\tthis.beginUpdate();
\tthis.currentEdit.add(change);
\tthis.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change));
\t// New global executed event
\tthis.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
\tthis.endUpdate();
};

/**
 * Function: beginUpdate
 * 
 * Increments the <updateLevel> by one. The event notification
 * is queued until <updateLevel> reaches 0 by use of
 * <endUpdate>.
 *
 * All changes on <mxGraphModel> are transactional,
 * that is, they are executed in a single undoable change
 * on the model (without transaction isolation).
 * Therefore, if you want to combine any
 * number of changes into a single undoable change,
 * you should group any two or more API calls that
 * modify the graph model between <beginUpdate>
 * and <endUpdate> calls as shown here:
 * 
 * (code)
 * var model = graph.getModel();
 * var parent = graph.getDefaultParent();
 * var index = model.getChildCount(parent);
 * model.beginUpdate();
 * try
 * {
 *   model.add(parent, v1, index);
 *   model.add(parent, v2, index+1);
 * }
 * finally
 * {
 *   model.endUpdate();
 * }
 * (end)
 * 
 * Of course there is a shortcut for appending a
 * sequence of cells into the default parent:
 * 
 * (code)
 * graph.addCells([v1, v2]).
 * (end)
 */
mxGraphModel.prototype.beginUpdate = function()
{
\tthis.updateLevel++;
\tthis.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE));
\t
\tif (this.updateLevel == 1)
\t{
\t\tthis.fireEvent(new mxEventObject(mxEvent.START_EDIT));
\t}
};

/**
 * Function: endUpdate
 * 
 * Decrements the <updateLevel> by one and fires an <undo>
 * event if the <updateLevel> reaches 0. This function
 * indirectly fires a <change> event by invoking the notify
 * function on the <currentEdit> und then creates a new
 * <currentEdit> using <createUndoableEdit>.
 *
 * The <undo> event is fired only once per edit, whereas
 * the <change> event is fired whenever the notify
 * function is invoked, that is, on undo and redo of
 * the edit.
 */
mxGraphModel.prototype.endUpdate = function()
{
\tthis.updateLevel--;
\t
\tif (this.updateLevel == 0)
\t{
\t\tthis.fireEvent(new mxEventObject(mxEvent.END_EDIT));
\t}
\t
\tif (!this.endingUpdate)
\t{
\t\tthis.endingUpdate = this.updateLevel == 0;
\t\tthis.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit));

\t\ttry
\t\t{\t\t
\t\t\tif (this.endingUpdate && !this.currentEdit.isEmpty())
\t\t\t{
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit));
\t\t\t\tvar tmp = this.currentEdit;
\t\t\t\tthis.currentEdit = this.createUndoableEdit();
\t\t\t\ttmp.notify();
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp));
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.endingUpdate = false;
\t\t}
\t}
};

/**
 * Function: createUndoableEdit
 * 
 * Creates a new <mxUndoableEdit> that implements the
 * notify function to fire a <change> and <notify> event
 * through the <mxUndoableEdit>'s source.
 * 
 * Parameters:
 * 
 * significant - Optional boolean that specifies if the edit to be created is
 * significant. Default is true.
 */
mxGraphModel.prototype.createUndoableEdit = function(significant)
{
\tvar edit = new mxUndoableEdit(this, (significant != null) ? significant : true);
\t
\tedit.notify = function()
\t{
\t\t// LATER: Remove changes property (deprecated)
\t\tedit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
\t\t\t'edit', edit, 'changes', edit.changes));
\t\tedit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
\t\t\t'edit', edit, 'changes', edit.changes));
\t};
\t
\treturn edit;
};

/**
 * Function: mergeChildren
 * 
 * Merges the children of the given cell into the given target cell inside
 * this model. All cells are cloned unless there is a corresponding cell in
 * the model with the same id, in which case the source cell is ignored and
 * all edges are connected to the corresponding cell in this model. Edges
 * are considered to have no identity and are always cloned unless the
 * cloneAllEdges flag is set to false, in which case edges with the same
 * id in the target model are reconnected to reflect the terminals of the
 * source edges.
 */
mxGraphModel.prototype.mergeChildren = function(from, to, cloneAllEdges)
{
\tcloneAllEdges = (cloneAllEdges != null) ? cloneAllEdges : true;
\t
\tthis.beginUpdate();
\ttry
\t{
\t\tvar mapping = new Object();
\t\tthis.mergeChildrenImpl(from, to, cloneAllEdges, mapping);
\t\t
\t\t// Post-processes all edges in the mapping and
\t\t// reconnects the terminals to the corresponding
\t\t// cells in the target model
\t\tfor (var key in mapping)
\t\t{
\t\t\tvar cell = mapping[key];
\t\t\tvar terminal = this.getTerminal(cell, true);

\t\t\tif (terminal != null)
\t\t\t{
\t\t\t\tterminal = mapping[mxCellPath.create(terminal)];
\t\t\t\tthis.setTerminal(cell, terminal, true);
\t\t\t}
\t\t\t
\t\t\tterminal = this.getTerminal(cell, false);
\t\t\t
\t\t\tif (terminal != null)
\t\t\t{
\t\t\t\tterminal = mapping[mxCellPath.create(terminal)];
\t\t\t\tthis.setTerminal(cell, terminal, false);
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tthis.endUpdate();
\t}
};

/**
 * Function: mergeChildren
 * 
 * Clones the children of the source cell into the given target cell in
 * this model and adds an entry to the mapping that maps from the source
 * cell to the target cell with the same id or the clone of the source cell
 * that was inserted into this model.
 */
mxGraphModel.prototype.mergeChildrenImpl = function(from, to, cloneAllEdges, mapping)
{
\tthis.beginUpdate();
\ttry
\t{
\t\tvar childCount = from.getChildCount();
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar cell = from.getChildAt(i);
\t\t\t
\t\t\tif (typeof(cell.getId) == 'function')
\t\t\t{
\t\t\t\tvar id = cell.getId();
\t\t\t\tvar target = (id != null && (!this.isEdge(cell) || !cloneAllEdges)) ?
\t\t\t\t\t\tthis.getCell(id) : null;
\t\t\t\t
\t\t\t\t// Clones and adds the child if no cell exists for the id
\t\t\t\tif (target == null)
\t\t\t\t{
\t\t\t\t\tvar clone = cell.clone();
\t\t\t\t\tclone.setId(id);
\t\t\t\t\t
\t\t\t\t\t// Sets the terminals from the original cell to the clone
\t\t\t\t\t// because the lookup uses strings not cells in JS
\t\t\t\t\tclone.setTerminal(cell.getTerminal(true), true);
\t\t\t\t\tclone.setTerminal(cell.getTerminal(false), false);
\t\t\t\t\t
\t\t\t\t\t// Do *NOT* use model.add as this will move the edge away
\t\t\t\t\t// from the parent in updateEdgeParent if maintainEdgeParent
\t\t\t\t\t// is enabled in the target model
\t\t\t\t\ttarget = to.insert(clone);
\t\t\t\t\tthis.cellAdded(target);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Stores the mapping for later reconnecting edges
\t\t\t\tmapping[mxCellPath.create(cell)] = target;
\t\t\t\t
\t\t\t\t// Recurses
\t\t\t\tthis.mergeChildrenImpl(cell, target, cloneAllEdges, mapping);
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tthis.endUpdate();
\t}
};

/**
 * Function: getParents
 * 
 * Returns an array that represents the set (no duplicates) of all parents
 * for the given array of cells.
 * 
 * Parameters:
 * 
 * cells - Array of cells whose parents should be returned.
 */
mxGraphModel.prototype.getParents = function(cells)
{
\tvar parents = [];
\t
\tif (cells != null)
\t{
\t\tvar dict = new mxDictionary();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar parent = this.getParent(cells[i]);
\t\t\t
\t\t\tif (parent != null && !dict.get(parent))
\t\t\t{
\t\t\t\tdict.put(parent, true);
\t\t\t\tparents.push(parent);
\t\t\t}
\t\t}
\t}
\t
\treturn parents;
};

//
// Cell Cloning
//

/**
 * Function: cloneCell
 * 
 * Returns a deep clone of the given <mxCell> (including
 * the children) which is created using <cloneCells>.
 *
 * Parameters:
 * 
 * cell - <mxCell> to be cloned.
 * includeChildren - Optional boolean indicating if the cells should be cloned
 * with all descendants. Default is true.
 */
mxGraphModel.prototype.cloneCell = function(cell, includeChildren)
{
\tif (cell != null)
\t{
\t\treturn this.cloneCells([cell], includeChildren)[0];
\t}
\t
\treturn null;
};

/**
 * Function: cloneCells
 * 
 * Returns an array of clones for the given array of <mxCells>.
 * Depending on the value of includeChildren, a deep clone is created for
 * each cell. Connections are restored based if the corresponding
 * cell is contained in the passed in array.
 *
 * Parameters:
 * 
 * cells - Array of <mxCell> to be cloned.
 * includeChildren - Optional boolean indicating if the cells should be cloned
 * with all descendants. Default is true.
 * mapping - Optional mapping for existing clones.
 */
mxGraphModel.prototype.cloneCells = function(cells, includeChildren, mapping)
{
\tincludeChildren = (includeChildren != null) ? includeChildren : true;
\tmapping = (mapping != null) ? mapping : new Object();
\tvar clones = [];
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tif (cells[i] != null)
\t\t{
\t\t\tclones.push(this.cloneCellImpl(cells[i], mapping, includeChildren));
\t\t}
\t\telse
\t\t{
\t\t\tclones.push(null);
\t\t}
\t}
\t
\tfor (var i = 0; i < clones.length; i++)
\t{
\t\tif (clones[i] != null)
\t\t{
\t\t\tthis.restoreClone(clones[i], cells[i], mapping);
\t\t}
\t}
\t
\treturn clones;
};
\t\t\t
/**
 * Function: cloneCellImpl
 * 
 * Inner helper method for cloning cells recursively.
 */
mxGraphModel.prototype.cloneCellImpl = function(cell, mapping, includeChildren)
{
\tvar ident = mxObjectIdentity.get(cell);
\tvar clone = mapping[ident];
\t
\tif (clone == null)
\t{
\t\tclone = this.cellCloned(cell);
\t\tmapping[ident] = clone;

\t\tif (includeChildren)
\t\t{
\t\t\tvar childCount = this.getChildCount(cell);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tvar cloneChild = this.cloneCellImpl(
\t\t\t\t\tthis.getChildAt(cell, i), mapping, true);
\t\t\t\tclone.insert(cloneChild);
\t\t\t}
\t\t}
\t}
\t
\treturn clone;
};

/**
 * Function: cellCloned
 * 
 * Hook for cloning the cell. This returns cell.clone() or
 * any possible exceptions.
 */
mxGraphModel.prototype.cellCloned = function(cell)
{
\treturn cell.clone();
};

/**
 * Function: restoreClone
 * 
 * Inner helper method for restoring the connections in
 * a network of cloned cells.
 */
mxGraphModel.prototype.restoreClone = function(clone, cell, mapping)
{
\tvar source = this.getTerminal(cell, true);
\t
\tif (source != null)
\t{
\t\tvar tmp = mapping[mxObjectIdentity.get(source)];
\t\t
\t\tif (tmp != null)
\t\t{
\t\t\ttmp.insertEdge(clone, true);
\t\t}
\t}
\t
\tvar target = this.getTerminal(cell, false);
\t
\tif (target != null)
\t{
\t\tvar tmp = mapping[mxObjectIdentity.get(target)];
\t\t
\t\tif (tmp != null)
\t\t{\t
\t\t\ttmp.insertEdge(clone, false);
\t\t}
\t}
\t
\tvar childCount = this.getChildCount(clone);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tthis.restoreClone(this.getChildAt(clone, i),
\t\t\tthis.getChildAt(cell, i), mapping);
\t}
};

//
// Atomic changes
//

/**
 * Class: mxRootChange
 * 
 * Action to change the root in a model.
 *
 * Constructor: mxRootChange
 * 
 * Constructs a change of the root in the
 * specified model.
 */
function mxRootChange(model, root)
{
\tthis.model = model;
\tthis.root = root;
\tthis.previous = root;
};

/**
 * Function: execute
 * 
 * Carries out a change of the root using
 * <mxGraphModel.rootChanged>.
 */
mxRootChange.prototype.execute = function()
{
\tthis.root = this.previous;
\tthis.previous = this.model.rootChanged(this.previous);
};

/**
 * Class: mxChildChange
 * 
 * Action to add or remove a child in a model.
 *
 * Constructor: mxChildChange
 * 
 * Constructs a change of a child in the
 * specified model.
 */
function mxChildChange(model, parent, child, index)
{
\tthis.model = model;
\tthis.parent = parent;
\tthis.previous = parent;
\tthis.child = child;
\tthis.index = index;
\tthis.previousIndex = index;
};

/**
 * Function: execute
 * 
 * Changes the parent of <child> using
 * <mxGraphModel.parentForCellChanged> and
 * removes or restores the cell's
 * connections.
 */
mxChildChange.prototype.execute = function()
{
\tif (this.child != null)
\t{
\t\tvar tmp = this.model.getParent(this.child);
\t\tvar tmp2 = (tmp != null) ? tmp.getIndex(this.child) : 0;
\t\t
\t\tif (this.previous == null)
\t\t{
\t\t\tthis.connect(this.child, false);
\t\t}
\t\t
\t\ttmp = this.model.parentForCellChanged(
\t\t\tthis.child, this.previous, this.previousIndex);
\t\t\t
\t\tif (this.previous != null)
\t\t{
\t\t\tthis.connect(this.child, true);
\t\t}
\t\t
\t\tthis.parent = this.previous;
\t\tthis.previous = tmp;
\t\tthis.index = this.previousIndex;
\t\tthis.previousIndex = tmp2;
\t}
};

/**
 * Function: disconnect
 * 
 * Disconnects the given cell recursively from its
 * terminals and stores the previous terminal in the
 * cell's terminals.
 */
mxChildChange.prototype.connect = function(cell, isConnect)
{
\tisConnect = (isConnect != null) ? isConnect : true;
\t
\tvar source = cell.getTerminal(true);
\tvar target = cell.getTerminal(false);
\t
\tif (source != null)
\t{
\t\tif (isConnect)
\t\t{
\t\t\tthis.model.terminalForCellChanged(cell, source, true);
\t\t}
\t\telse
\t\t{
\t\t\tthis.model.terminalForCellChanged(cell, null, true);
\t\t}
\t}
\t
\tif (target != null)
\t{
\t\tif (isConnect)
\t\t{
\t\t\tthis.model.terminalForCellChanged(cell, target, false);
\t\t}
\t\telse
\t\t{
\t\t\tthis.model.terminalForCellChanged(cell, null, false);
\t\t}
\t}
\t
\tcell.setTerminal(source, true);
\tcell.setTerminal(target, false);
\t
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i=0; i<childCount; i++)
\t{
\t\tthis.connect(this.model.getChildAt(cell, i), isConnect);
\t}
};

/**
 * Class: mxTerminalChange
 * 
 * Action to change a terminal in a model.
 *
 * Constructor: mxTerminalChange
 * 
 * Constructs a change of a terminal in the 
 * specified model.
 */
function mxTerminalChange(model, cell, terminal, source)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.terminal = terminal;
\tthis.previous = terminal;
\tthis.source = source;
};

/**
 * Function: execute
 * 
 * Changes the terminal of <cell> to <previous> using
 * <mxGraphModel.terminalForCellChanged>.
 */
mxTerminalChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.terminal = this.previous;
\t\tthis.previous = this.model.terminalForCellChanged(
\t\t\tthis.cell, this.previous, this.source);
\t}
};

/**
 * Class: mxValueChange
 * 
 * Action to change a user object in a model.
 *
 * Constructor: mxValueChange
 * 
 * Constructs a change of a user object in the 
 * specified model.
 */
function mxValueChange(model, cell, value)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.value = value;
\tthis.previous = value;
};

/**
 * Function: execute
 * 
 * Changes the value of <cell> to <previous> using
 * <mxGraphModel.valueForCellChanged>.
 */
mxValueChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.value = this.previous;
\t\tthis.previous = this.model.valueForCellChanged(
\t\t\tthis.cell, this.previous);
\t}
};

/**
 * Class: mxStyleChange
 * 
 * Action to change a cell's style in a model.
 *
 * Constructor: mxStyleChange
 * 
 * Constructs a change of a style in the
 * specified model.
 */
function mxStyleChange(model, cell, style)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.style = style;
\tthis.previous = style;
};

/**
 * Function: execute
 * 
 * Changes the style of <cell> to <previous> using
 * <mxGraphModel.styleForCellChanged>.
 */
mxStyleChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.style = this.previous;
\t\tthis.previous = this.model.styleForCellChanged(
\t\t\tthis.cell, this.previous);
\t}
};

/**
 * Class: mxGeometryChange
 * 
 * Action to change a cell's geometry in a model.
 *
 * Constructor: mxGeometryChange
 * 
 * Constructs a change of a geometry in the
 * specified model.
 */
function mxGeometryChange(model, cell, geometry)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.geometry = geometry;
\tthis.previous = geometry;
};

/**
 * Function: execute
 * 
 * Changes the geometry of <cell> ro <previous> using
 * <mxGraphModel.geometryForCellChanged>.
 */
mxGeometryChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.geometry = this.previous;
\t\tthis.previous = this.model.geometryForCellChanged(
\t\t\tthis.cell, this.previous);
\t}
};

/**
 * Class: mxCollapseChange
 * 
 * Action to change a cell's collapsed state in a model.
 *
 * Constructor: mxCollapseChange
 * 
 * Constructs a change of a collapsed state in the
 * specified model.
 */
function mxCollapseChange(model, cell, collapsed)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.collapsed = collapsed;
\tthis.previous = collapsed;
};

/**
 * Function: execute
 * 
 * Changes the collapsed state of <cell> to <previous> using
 * <mxGraphModel.collapsedStateForCellChanged>.
 */
mxCollapseChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.collapsed = this.previous;
\t\tthis.previous = this.model.collapsedStateForCellChanged(
\t\t\tthis.cell, this.previous);
\t}
};

/**
 * Class: mxVisibleChange
 * 
 * Action to change a cell's visible state in a model.
 *
 * Constructor: mxVisibleChange
 * 
 * Constructs a change of a visible state in the
 * specified model.
 */
function mxVisibleChange(model, cell, visible)
{
\tthis.model = model;
\tthis.cell = cell;
\tthis.visible = visible;
\tthis.previous = visible;
};

/**
 * Function: execute
 * 
 * Changes the visible state of <cell> to <previous> using
 * <mxGraphModel.visibleStateForCellChanged>.
 */
mxVisibleChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tthis.visible = this.previous;
\t\tthis.previous = this.model.visibleStateForCellChanged(
\t\t\tthis.cell, this.previous);
\t}
};

/**
 * Class: mxCellAttributeChange
 * 
 * Action to change the attribute of a cell's user object.
 * There is no method on the graph model that uses this
 * action. To use the action, you can use the code shown
 * in the example below.
 * 
 * Example:
 * 
 * To change the attributeName in the cell's user object
 * to attributeValue, use the following code:
 * 
 * (code)
 * model.beginUpdate();
 * try
 * {
 *   var edit = new mxCellAttributeChange(
 *     cell, attributeName, attributeValue);
 *   model.execute(edit);
 * }
 * finally
 * {
 *   model.endUpdate();
 * } 
 * (end)
 *
 * Constructor: mxCellAttributeChange
 * 
 * Constructs a change of a attribute of the DOM node
 * stored as the value of the given <mxCell>.
 */
function mxCellAttributeChange(cell, attribute, value)
{
\tthis.cell = cell;
\tthis.attribute = attribute;
\tthis.value = value;
\tthis.previous = value;
};

/**
 * Function: execute
 * 
 * Changes the attribute of the cell's user object by
 * using <mxCell.setAttribute>.
 */
mxCellAttributeChange.prototype.execute = function()
{
\tif (this.cell != null)
\t{
\t\tvar tmp = this.cell.getAttribute(this.attribute);
\t\t
\t\tif (this.previous == null)
\t\t{
\t\t\tthis.cell.value.removeAttribute(this.attribute);
\t\t}
\t\telse
\t\t{
\t\t\tthis.cell.setAttribute(this.attribute, this.previous);
\t\t}
\t\t
\t\tthis.previous = tmp;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCell
 *
 * Cells are the elements of the graph model. They represent the state
 * of the groups, vertices and edges in a graph.
 * 
 * Custom attributes:
 * 
 * For custom attributes we recommend using an XML node as the value of a cell.
 * The following code can be used to create a cell with an XML node as the
 * value:
 * 
 * (code)
 * var doc = mxUtils.createXmlDocument();
 * var node = doc.createElement('MyNode')
 * node.setAttribute('label', 'MyLabel');
 * node.setAttribute('attribute1', 'value1');
 * graph.insertVertex(graph.getDefaultParent(), null, node, 40, 40, 80, 30);
 * (end)
 * 
 * For the label to work, <mxGraph.convertValueToString> and
 * <mxGraph.cellLabelChanged> should be overridden as follows:
 * 
 * (code)
 * graph.convertValueToString = function(cell)
 * {
 *   if (mxUtils.isNode(cell.value))
 *   {
 *     return cell.getAttribute('label', '')
 *   }
 * };
 * 
 * var cellLabelChanged = graph.cellLabelChanged;
 * graph.cellLabelChanged = function(cell, newValue, autoSize)
 * {
 *   if (mxUtils.isNode(cell.value))
 *   {
 *     // Clones the value for correct undo/redo
 *     var elt = cell.value.cloneNode(true);
 *     elt.setAttribute('label', newValue);
 *     newValue = elt;
 *   }
 *   
 *   cellLabelChanged.apply(this, arguments);
 * };
 * (end)
 * 
 * Callback: onInit
 *
 * Called from within the constructor.
 * 
 * Constructor: mxCell
 *
 * Constructs a new cell to be used in a graph model.
 * This method invokes <onInit> upon completion.
 * 
 * Parameters:
 * 
 * value - Optional object that represents the cell value.
 * geometry - Optional <mxGeometry> that specifies the geometry.
 * style - Optional formatted string that defines the style.
 */
function mxCell(value, geometry, style)
{
\tthis.value = value;
\tthis.setGeometry(geometry);
\tthis.setStyle(style);
\t
\tif (this.onInit != null)
\t{
\t\tthis.onInit();
\t}
};

/**
 * Variable: id
 *
 * Holds the Id. Default is null.
 */
mxCell.prototype.id = null;

/**
 * Variable: value
 *
 * Holds the user object. Default is null.
 */
mxCell.prototype.value = null;

/**
 * Variable: geometry
 *
 * Holds the <mxGeometry>. Default is null.
 */
mxCell.prototype.geometry = null;

/**
 * Variable: style
 *
 * Holds the style as a string of the form [(stylename|key=value);]. Default is
 * null.
 */
mxCell.prototype.style = null;

/**
 * Variable: vertex
 *
 * Specifies whether the cell is a vertex. Default is false.
 */
mxCell.prototype.vertex = false;

/**
 * Variable: edge
 *
 * Specifies whether the cell is an edge. Default is false.
 */
mxCell.prototype.edge = false;

/**
 * Variable: connectable
 *
 * Specifies whether the cell is connectable. Default is true.
 */
mxCell.prototype.connectable = true;

/**
 * Variable: visible
 *
 * Specifies whether the cell is visible. Default is true.
 */
mxCell.prototype.visible = true;

/**
 * Variable: collapsed
 *
 * Specifies whether the cell is collapsed. Default is false.
 */
mxCell.prototype.collapsed = false;

/**
 * Variable: parent
 *
 * Reference to the parent cell.
 */
mxCell.prototype.parent = null;

/**
 * Variable: source
 *
 * Reference to the source terminal.
 */
mxCell.prototype.source = null;

/**
 * Variable: target
 *
 * Reference to the target terminal.
 */
mxCell.prototype.target = null;

/**
 * Variable: children
 *
 * Holds the child cells.
 */
mxCell.prototype.children = null;

/**
 * Variable: edges
 *
 * Holds the edges.
 */
mxCell.prototype.edges = null;

/**
 * Variable: mxTransient
 *
 * List of members that should not be cloned inside <clone>. This field is
 * passed to <mxUtils.clone> and is not made persistent in <mxCellCodec>.
 * This is not a convention for all classes, it is only used in this class
 * to mark transient fields since transient modifiers are not supported by
 * the language.
 */
mxCell.prototype.mxTransient = ['id', 'value', 'parent', 'source',
                                'target', 'children', 'edges'];

/**
 * Function: getId
 *
 * Returns the Id of the cell as a string.
 */
mxCell.prototype.getId = function()
{
\treturn this.id;
};
\t\t
/**
 * Function: setId
 *
 * Sets the Id of the cell to the given string.
 */
mxCell.prototype.setId = function(id)
{
\tthis.id = id;
};

/**
 * Function: getValue
 *
 * Returns the user object of the cell. The user
 * object is stored in <value>.
 */
mxCell.prototype.getValue = function()
{
\treturn this.value;
};
\t\t
/**
 * Function: setValue
 *
 * Sets the user object of the cell. The user object
 * is stored in <value>.
 */
mxCell.prototype.setValue = function(value)
{
\tthis.value = value;
};

/**
 * Function: valueChanged
 *
 * Changes the user object after an in-place edit
 * and returns the previous value. This implementation
 * replaces the user object with the given value and
 * returns the old user object.
 */
mxCell.prototype.valueChanged = function(newValue)
{
\tvar previous = this.getValue();
\tthis.setValue(newValue);
\t
\treturn previous;
};

/**
 * Function: getGeometry
 *
 * Returns the <mxGeometry> that describes the <geometry>.
 */
mxCell.prototype.getGeometry = function()
{
\treturn this.geometry;
};

/**
 * Function: setGeometry
 *
 * Sets the <mxGeometry> to be used as the <geometry>.
 */
mxCell.prototype.setGeometry = function(geometry)
{
\tthis.geometry = geometry;
};

/**
 * Function: getStyle
 *
 * Returns a string that describes the <style>.
 */
mxCell.prototype.getStyle = function()
{
\treturn this.style;
};

/**
 * Function: setStyle
 *
 * Sets the string to be used as the <style>.
 */
mxCell.prototype.setStyle = function(style)
{
\tthis.style = style;
};

/**
 * Function: isVertex
 *
 * Returns true if the cell is a vertex.
 */
mxCell.prototype.isVertex = function()
{
\treturn this.vertex != 0;
};

/**
 * Function: setVertex
 *
 * Specifies if the cell is a vertex. This should only be assigned at
 * construction of the cell and not be changed during its lifecycle.
 * 
 * Parameters:
 * 
 * vertex - Boolean that specifies if the cell is a vertex.
 */
mxCell.prototype.setVertex = function(vertex)
{
\tthis.vertex = vertex;
};

/**
 * Function: isEdge
 *
 * Returns true if the cell is an edge.
 */
mxCell.prototype.isEdge = function()
{
\treturn this.edge != 0;
};
\t
/**
 * Function: setEdge
 * 
 * Specifies if the cell is an edge. This should only be assigned at
 * construction of the cell and not be changed during its lifecycle.
 * 
 * Parameters:
 * 
 * edge - Boolean that specifies if the cell is an edge.
 */
mxCell.prototype.setEdge = function(edge)
{
\tthis.edge = edge;
};

/**
 * Function: isConnectable
 *
 * Returns true if the cell is connectable.
 */
mxCell.prototype.isConnectable = function()
{
\treturn this.connectable != 0;
};

/**
 * Function: setConnectable
 *
 * Sets the connectable state.
 * 
 * Parameters:
 * 
 * connectable - Boolean that specifies the new connectable state.
 */
mxCell.prototype.setConnectable = function(connectable)
{
\tthis.connectable = connectable;
};

/**
 * Function: isVisible
 *
 * Returns true if the cell is visibile.
 */
mxCell.prototype.isVisible = function()
{
\treturn this.visible != 0;
};

/**
 * Function: setVisible
 *
 * Specifies if the cell is visible.
 * 
 * Parameters:
 * 
 * visible - Boolean that specifies the new visible state.
 */
mxCell.prototype.setVisible = function(visible)
{
\tthis.visible = visible;
};

/**
 * Function: isCollapsed
 *
 * Returns true if the cell is collapsed.
 */
mxCell.prototype.isCollapsed = function()
{
\treturn this.collapsed != 0;
};

/**
 * Function: setCollapsed
 *
 * Sets the collapsed state.
 * 
 * Parameters:
 * 
 * collapsed - Boolean that specifies the new collapsed state.
 */
mxCell.prototype.setCollapsed = function(collapsed)
{
\tthis.collapsed = collapsed;
};

/**
 * Function: getParent
 *
 * Returns the cell's parent.
 */
mxCell.prototype.getParent = function()
{
\treturn this.parent;
};

/**
 * Function: setParent
 *
 * Sets the parent cell.
 * 
 * Parameters:
 * 
 * parent - <mxCell> that represents the new parent.
 */
mxCell.prototype.setParent = function(parent)
{
\tthis.parent = parent;
};

/**
 * Function: getTerminal
 *
 * Returns the source or target terminal.
 * 
 * Parameters:
 * 
 * source - Boolean that specifies if the source terminal should be
 * returned.
 */
mxCell.prototype.getTerminal = function(source)
{
\treturn (source) ? this.source : this.target;
};

/**
 * Function: setTerminal
 *
 * Sets the source or target terminal and returns the new terminal.
 * 
 * Parameters:
 * 
 * terminal - <mxCell> that represents the new source or target terminal.
 * isSource - Boolean that specifies if the source or target terminal
 * should be set.
 */
mxCell.prototype.setTerminal = function(terminal, isSource)
{
\tif (isSource)
\t{
\t\tthis.source = terminal;
\t}
\telse
\t{
\t\tthis.target = terminal;
\t}
\t
\treturn terminal;
};

/**
 * Function: getChildCount
 *
 * Returns the number of child cells.
 */
mxCell.prototype.getChildCount = function()
{
\treturn (this.children == null) ? 0 : this.children.length;
};

/**
 * Function: getIndex
 *
 * Returns the index of the specified child in the child array.
 * 
 * Parameters:
 * 
 * child - Child whose index should be returned.
 */
mxCell.prototype.getIndex = function(child)
{
\treturn mxUtils.indexOf(this.children, child);
};

/**
 * Function: getChildAt
 *
 * Returns the child at the specified index.
 * 
 * Parameters:
 * 
 * index - Integer that specifies the child to be returned.
 */
mxCell.prototype.getChildAt = function(index)
{
\treturn (this.children == null) ? null : this.children[index];
};

/**
 * Function: insert
 *
 * Inserts the specified child into the child array at the specified index
 * and updates the parent reference of the child. If not childIndex is
 * specified then the child is appended to the child array. Returns the
 * inserted child.
 * 
 * Parameters:
 * 
 * child - <mxCell> to be inserted or appended to the child array.
 * index - Optional integer that specifies the index at which the child
 * should be inserted into the child array.
 */
mxCell.prototype.insert = function(child, index)
{
\tif (child != null)
\t{
\t\tif (index == null)
\t\t{
\t\t\tindex = this.getChildCount();
\t\t\t
\t\t\tif (child.getParent() == this)
\t\t\t{
\t\t\t\tindex--;
\t\t\t}
\t\t}

\t\tchild.removeFromParent();
\t\tchild.setParent(this);
\t\t
\t\tif (this.children == null)
\t\t{
\t\t\tthis.children = [];
\t\t\tthis.children.push(child);
\t\t}
\t\telse
\t\t{
\t\t\tthis.children.splice(index, 0, child);
\t\t}
\t}
\t
\treturn child;
};

/**
 * Function: remove
 *
 * Removes the child at the specified index from the child array and
 * returns the child that was removed. Will remove the parent reference of
 * the child.
 * 
 * Parameters:
 * 
 * index - Integer that specifies the index of the child to be
 * removed.
 */
mxCell.prototype.remove = function(index)
{
\tvar child = null;
\t
\tif (this.children != null && index >= 0)
\t{
\t\tchild = this.getChildAt(index);
\t\t
\t\tif (child != null)
\t\t{
\t\t\tthis.children.splice(index, 1);
\t\t\tchild.setParent(null);
\t\t}
\t}
\t
\treturn child;
};

/**
 * Function: removeFromParent
 *
 * Removes the cell from its parent.
 */
mxCell.prototype.removeFromParent = function()
{
\tif (this.parent != null)
\t{
\t\tvar index = this.parent.getIndex(this);
\t\tthis.parent.remove(index);
\t}
};

/**
 * Function: getEdgeCount
 *
 * Returns the number of edges in the edge array.
 */
mxCell.prototype.getEdgeCount = function()
{
\treturn (this.edges == null) ? 0 : this.edges.length;
};

/**
 * Function: getEdgeIndex
 *
 * Returns the index of the specified edge in <edges>.
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose index in <edges> should be returned.
 */
mxCell.prototype.getEdgeIndex = function(edge)
{
\treturn mxUtils.indexOf(this.edges, edge);
};

/**
 * Function: getEdgeAt
 *
 * Returns the edge at the specified index in <edges>.
 * 
 * Parameters:
 * 
 * index - Integer that specifies the index of the edge to be returned.
 */
mxCell.prototype.getEdgeAt = function(index)
{
\treturn (this.edges == null) ? null : this.edges[index];
};

/**
 * Function: insertEdge
 *
 * Inserts the specified edge into the edge array and returns the edge.
 * Will update the respective terminal reference of the edge.
 * 
 * Parameters:
 * 
 * edge - <mxCell> to be inserted into the edge array.
 * isOutgoing - Boolean that specifies if the edge is outgoing.
 */
mxCell.prototype.insertEdge = function(edge, isOutgoing)
{
\tif (edge != null)
\t{
\t\tedge.removeFromTerminal(isOutgoing);
\t\tedge.setTerminal(this, isOutgoing);
\t\t
\t\tif (this.edges == null ||
\t\t\tedge.getTerminal(!isOutgoing) != this ||
\t\t\tmxUtils.indexOf(this.edges, edge) < 0)
\t\t{
\t\t\tif (this.edges == null)
\t\t\t{
\t\t\t\tthis.edges = [];
\t\t\t}
\t\t\t
\t\t\tthis.edges.push(edge);
\t\t}
\t}
\t
\treturn edge;
};

/**
 * Function: removeEdge
 *
 * Removes the specified edge from the edge array and returns the edge.
 * Will remove the respective terminal reference from the edge.
 * 
 * Parameters:
 * 
 * edge - <mxCell> to be removed from the edge array.
 * isOutgoing - Boolean that specifies if the edge is outgoing.
 */
mxCell.prototype.removeEdge = function(edge, isOutgoing)
{
\tif (edge != null)
\t{
\t\tif (edge.getTerminal(!isOutgoing) != this &&
\t\t\tthis.edges != null)
\t\t{
\t\t\tvar index = this.getEdgeIndex(edge);
\t\t\t
\t\t\tif (index >= 0)
\t\t\t{
\t\t\t\tthis.edges.splice(index, 1);
\t\t\t}
\t\t}
\t\t
\t\tedge.setTerminal(null, isOutgoing);
\t}
\t
\treturn edge;
};

/**
 * Function: removeFromTerminal
 *
 * Removes the edge from its source or target terminal.
 * 
 * Parameters:
 * 
 * isSource - Boolean that specifies if the edge should be removed from its
 * source or target terminal.
 */
mxCell.prototype.removeFromTerminal = function(isSource)
{
\tvar terminal = this.getTerminal(isSource);
\t
\tif (terminal != null)
\t{
\t\tterminal.removeEdge(this, isSource);
\t}
};

/**
 * Function: hasAttribute
 * 
 * Returns true if the user object is an XML node that contains the given
 * attribute.
 * 
 * Parameters:
 * 
 * name - Name of the attribute.
 */
mxCell.prototype.hasAttribute = function(name)
{
\tvar userObject = this.getValue();
\t
\treturn (userObject != null &&
\t\tuserObject.nodeType == mxConstants.NODETYPE_ELEMENT && userObject.hasAttribute) ?
\t\tuserObject.hasAttribute(name) : userObject.getAttribute(name) != null;
};

/**
 * Function: getAttribute
 *
 * Returns the specified attribute from the user object if it is an XML
 * node.
 * 
 * Parameters:
 * 
 * name - Name of the attribute whose value should be returned.
 * defaultValue - Optional default value to use if the attribute has no
 * value.
 */
mxCell.prototype.getAttribute = function(name, defaultValue)
{
\tvar userObject = this.getValue();
\t
\tvar val = (userObject != null &&
\t\tuserObject.nodeType == mxConstants.NODETYPE_ELEMENT) ?
\t\tuserObject.getAttribute(name) : null;
\t\t
\treturn (val != null) ? val : defaultValue;
};

/**
 * Function: setAttribute
 *
 * Sets the specified attribute on the user object if it is an XML node.
 * 
 * Parameters:
 * 
 * name - Name of the attribute whose value should be set.
 * value - New value of the attribute.
 */
mxCell.prototype.setAttribute = function(name, value)
{
\tvar userObject = this.getValue();
\t
\tif (userObject != null &&
\t\tuserObject.nodeType == mxConstants.NODETYPE_ELEMENT)
\t{
\t\tuserObject.setAttribute(name, value);
\t}
};

/**
 * Function: clone
 *
 * Returns a clone of the cell. Uses <cloneValue> to clone
 * the user object. All fields in <mxTransient> are ignored
 * during the cloning.
 */
mxCell.prototype.clone = function()
{
\tvar clone = mxUtils.clone(this, this.mxTransient);
\tclone.setValue(this.cloneValue());
\t
\treturn clone;
};

/**
 * Function: cloneValue
 *
 * Returns a clone of the cell's user object.
 */
mxCell.prototype.cloneValue = function()
{
\tvar value = this.getValue();
\t
\tif (value != null)
\t{
\t\tif (typeof(value.clone) == 'function')
\t\t{
\t\t\tvalue = value.clone();
\t\t}
\t\telse if (!isNaN(value.nodeType))
\t\t{
\t\t\tvalue = value.cloneNode(true);
\t\t}
\t}
\t
\treturn value;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGeometry
 * 
 * Extends <mxRectangle> to represent the geometry of a cell.
 * 
 * For vertices, the geometry consists of the x- and y-location, and the width
 * and height. For edges, the geometry consists of the optional terminal- and
 * control points. The terminal points are only required if an edge is
 * unconnected, and are stored in the <sourcePoint> and <targetPoint>
 * variables, respectively.
 * 
 * Example:
 * 
 * If an edge is unconnected, that is, it has no source or target terminal,
 * then a geometry with terminal points for a new edge can be defined as
 * follows.
 * 
 * (code)
 * geometry.setTerminalPoint(new mxPoint(x1, y1), true);
 * geometry.points = [new mxPoint(x2, y2)];
 * geometry.setTerminalPoint(new mxPoint(x3, y3), false);
 * (end)
 * 
 * Control points are used regardless of the connected state of an edge and may
 * be ignored or interpreted differently depending on the edge's <mxEdgeStyle>.
 * 
 * To disable automatic reset of control points after a cell has been moved or
 * resized, the the <mxGraph.resizeEdgesOnMove> and
 * <mxGraph.resetEdgesOnResize> may be used.
 *
 * Edge Labels:
 * 
 * Using the x- and y-coordinates of a cell's geometry, it is possible to
 * position the label on edges on a specific location on the actual edge shape
 * as it appears on the screen. The x-coordinate of an edge's geometry is used
 * to describe the distance from the center of the edge from -1 to 1 with 0
 * being the center of the edge and the default value. The y-coordinate of an
 * edge's geometry is used to describe the absolute, orthogonal distance in
 * pixels from that point. In addition, the <mxGeometry.offset> is used as an
 * absolute offset vector from the resulting point.
 * 
 * This coordinate system is applied if <relative> is true, otherwise the
 * offset defines the absolute vector from the edge's center point to the
 * label and the values for <x> and <y> are ignored.
 * 
 * The width and height parameter for edge geometries can be used to set the
 * label width and height (eg. for word wrapping).
 * 
 * Ports:
 * 
 * The term \"port\" refers to a relatively positioned, connectable child cell,
 * which is used to specify the connection between the parent and another cell
 * in the graph. Ports are typically modeled as vertices with relative
 * geometries.
 * 
 * Offsets:
 * 
 * The <offset> field is interpreted in 3 different ways, depending on the cell
 * and the geometry. For edges, the offset defines the absolute offset for the
 * edge label. For relative geometries, the offset defines the absolute offset
 * for the origin (top, left corner) of the vertex, otherwise the offset
 * defines the absolute offset for the label inside the vertex or group.
 * 
 * Constructor: mxGeometry
 *
 * Constructs a new object to describe the size and location of a vertex or
 * the control points of an edge.
 */
function mxGeometry(x, y, width, height)
{
\tmxRectangle.call(this, x, y, width, height);
};

/**
 * Extends mxRectangle.
 */
mxGeometry.prototype = new mxRectangle();
mxGeometry.prototype.constructor = mxGeometry;

/**
 * Variable: TRANSLATE_CONTROL_POINTS
 * 
 * Global switch to translate the points in translate. Default is true.
 */
mxGeometry.prototype.TRANSLATE_CONTROL_POINTS = true;

/**
 * Variable: alternateBounds
 *
 * Stores alternate values for x, y, width and height in a rectangle. See
 * <swap> to exchange the values. Default is null.
 */
mxGeometry.prototype.alternateBounds = null;

/**
 * Variable: sourcePoint
 *
 * Defines the source <mxPoint> of the edge. This is used if the
 * corresponding edge does not have a source vertex. Otherwise it is
 * ignored. Default is  null.
 */
mxGeometry.prototype.sourcePoint = null;

/**
 * Variable: targetPoint
 *
 * Defines the target <mxPoint> of the edge. This is used if the
 * corresponding edge does not have a target vertex. Otherwise it is
 * ignored. Default is null.
 */
mxGeometry.prototype.targetPoint = null;

/**
 * Variable: points
 *
 * Array of <mxPoints> which specifies the control points along the edge.
 * These points are the intermediate points on the edge, for the endpoints
 * use <targetPoint> and <sourcePoint> or set the terminals of the edge to
 * a non-null value. Default is null.
 */
mxGeometry.prototype.points = null;

/**
 * Variable: offset
 *
 * For edges, this holds the offset (in pixels) from the position defined
 * by <x> and <y> on the edge. For relative geometries (for vertices), this
 * defines the absolute offset from the point defined by the relative
 * coordinates. For absolute geometries (for vertices), this defines the
 * offset for the label. Default is null.
 */
mxGeometry.prototype.offset = null;

/**
 * Variable: relative
 *
 * Specifies if the coordinates in the geometry are to be interpreted as
 * relative coordinates. For edges, this is used to define the location of
 * the edge label relative to the edge as rendered on the display. For
 * vertices, this specifies the relative location inside the bounds of the
 * parent cell.
 * 
 * If this is false, then the coordinates are relative to the origin of the
 * parent cell or, for edges, the edge label position is relative to the
 * center of the edge as rendered on screen.
 * 
 * Default is false.
 */
mxGeometry.prototype.relative = false;

/**
 * Function: swap
 * 
 * Swaps the x, y, width and height with the values stored in
 * <alternateBounds> and puts the previous values into <alternateBounds> as
 * a rectangle. This operation is carried-out in-place, that is, using the
 * existing geometry instance. If this operation is called during a graph
 * model transactional change, then the geometry should be cloned before
 * calling this method and setting the geometry of the cell using
 * <mxGraphModel.setGeometry>.
 */
mxGeometry.prototype.swap = function()
{
\tif (this.alternateBounds != null)
\t{
\t\tvar old = new mxRectangle(
\t\t\tthis.x, this.y, this.width, this.height);

\t\tthis.x = this.alternateBounds.x;
\t\tthis.y = this.alternateBounds.y;
\t\tthis.width = this.alternateBounds.width;
\t\tthis.height = this.alternateBounds.height;

\t\tthis.alternateBounds = old;
\t}
};

/**
 * Function: getTerminalPoint
 * 
 * Returns the <mxPoint> representing the source or target point of this
 * edge. This is only used if the edge has no source or target vertex.
 * 
 * Parameters:
 * 
 * isSource - Boolean that specifies if the source or target point
 * should be returned.
 */
mxGeometry.prototype.getTerminalPoint = function(isSource)
{
\treturn (isSource) ? this.sourcePoint : this.targetPoint;
};

/**
 * Function: setTerminalPoint
 * 
 * Sets the <sourcePoint> or <targetPoint> to the given <mxPoint> and
 * returns the new point.
 * 
 * Parameters:
 * 
 * point - Point to be used as the new source or target point.
 * isSource - Boolean that specifies if the source or target point
 * should be set.
 */
mxGeometry.prototype.setTerminalPoint = function(point, isSource)
{
\tif (isSource)
\t{
\t\tthis.sourcePoint = point;
\t}
\telse
\t{
\t\tthis.targetPoint = point;
\t}
\t
\treturn point;
};

/**
 * Function: rotate
 * 
 * Rotates the geometry by the given angle around the given center. That is,
 * <x> and <y> of the geometry, the <sourcePoint>, <targetPoint> and all
 * <points> are translated by the given amount. <x> and <y> are only
 * translated if <relative> is false.
 * 
 * Parameters:
 * 
 * angle - Number that specifies the rotation angle in degrees.
 * cx - <mxPoint> that specifies the center of the rotation.
 */
mxGeometry.prototype.rotate = function(angle, cx)
{
\tvar rad = mxUtils.toRadians(angle);
\tvar cos = Math.cos(rad);
\tvar sin = Math.sin(rad);
\t
\t// Rotates the geometry
\tif (!this.relative)
\t{
\t\tvar ct = new mxPoint(this.getCenterX(), this.getCenterY());
\t\tvar pt = mxUtils.getRotatedPoint(ct, cos, sin, cx);
\t\t
\t\tthis.x = Math.round(pt.x - this.width / 2);
\t\tthis.y = Math.round(pt.y - this.height / 2);
\t}

\t// Rotates the source point
\tif (this.sourcePoint != null)
\t{
\t\tvar pt = mxUtils.getRotatedPoint(this.sourcePoint, cos, sin, cx);
\t\tthis.sourcePoint.x = Math.round(pt.x);
\t\tthis.sourcePoint.y = Math.round(pt.y);
\t}
\t
\t// Translates the target point
\tif (this.targetPoint != null)
\t{
\t\tvar pt = mxUtils.getRotatedPoint(this.targetPoint, cos, sin, cx);
\t\tthis.targetPoint.x = Math.round(pt.x);
\t\tthis.targetPoint.y = Math.round(pt.y);\t
\t}
\t
\t// Translate the control points
\tif (this.points != null)
\t{
\t\tfor (var i = 0; i < this.points.length; i++)
\t\t{
\t\t\tif (this.points[i] != null)
\t\t\t{
\t\t\t\tvar pt = mxUtils.getRotatedPoint(this.points[i], cos, sin, cx);
\t\t\t\tthis.points[i].x = Math.round(pt.x);
\t\t\t\tthis.points[i].y = Math.round(pt.y);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: translate
 * 
 * Translates the geometry by the specified amount. That is, <x> and <y> of the
 * geometry, the <sourcePoint>, <targetPoint> and all <points> are translated
 * by the given amount. <x> and <y> are only translated if <relative> is false.
 * If <TRANSLATE_CONTROL_POINTS> is false, then <points> are not modified by
 * this function.
 * 
 * Parameters:
 * 
 * dx - Number that specifies the x-coordinate of the translation.
 * dy - Number that specifies the y-coordinate of the translation.
 */
mxGeometry.prototype.translate = function(dx, dy)
{
\tdx = parseFloat(dx);
\tdy = parseFloat(dy);
\t
\t// Translates the geometry
\tif (!this.relative)
\t{
\t\tthis.x = parseFloat(this.x) + dx;
\t\tthis.y = parseFloat(this.y) + dy;
\t}

\t// Translates the source point
\tif (this.sourcePoint != null)
\t{
\t\tthis.sourcePoint.x = parseFloat(this.sourcePoint.x) + dx;
\t\tthis.sourcePoint.y = parseFloat(this.sourcePoint.y) + dy;
\t}
\t
\t// Translates the target point
\tif (this.targetPoint != null)
\t{
\t\tthis.targetPoint.x = parseFloat(this.targetPoint.x) + dx;
\t\tthis.targetPoint.y = parseFloat(this.targetPoint.y) + dy;\t\t
\t}

\t// Translate the control points
\tif (this.TRANSLATE_CONTROL_POINTS && this.points != null)
\t{
\t\tfor (var i = 0; i < this.points.length; i++)
\t\t{
\t\t\tif (this.points[i] != null)
\t\t\t{
\t\t\t\tthis.points[i].x = parseFloat(this.points[i].x) + dx;
\t\t\t\tthis.points[i].y = parseFloat(this.points[i].y) + dy;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: scale
 * 
 * Scales the geometry by the given amount. That is, <x> and <y> of the
 * geometry, the <sourcePoint>, <targetPoint> and all <points> are scaled
 * by the given amount. <x>, <y>, <width> and <height> are only scaled if
 * <relative> is false. If <fixedAspect> is true, then the smaller value
 * is used to scale the width and the height.
 * 
 * Parameters:
 * 
 * sx - Number that specifies the horizontal scale factor.
 * sy - Number that specifies the vertical scale factor.
 * fixedAspect - Optional boolean to keep the aspect ratio fixed.
 */
mxGeometry.prototype.scale = function(sx, sy, fixedAspect)
{
\tsx = parseFloat(sx);
\tsy = parseFloat(sy);

\t// Translates the source point
\tif (this.sourcePoint != null)
\t{
\t\tthis.sourcePoint.x = parseFloat(this.sourcePoint.x) * sx;
\t\tthis.sourcePoint.y = parseFloat(this.sourcePoint.y) * sy;
\t}
\t
\t// Translates the target point
\tif (this.targetPoint != null)
\t{
\t\tthis.targetPoint.x = parseFloat(this.targetPoint.x) * sx;
\t\tthis.targetPoint.y = parseFloat(this.targetPoint.y) * sy;\t\t
\t}

\t// Translate the control points
\tif (this.points != null)
\t{
\t\tfor (var i = 0; i < this.points.length; i++)
\t\t{
\t\t\tif (this.points[i] != null)
\t\t\t{
\t\t\t\tthis.points[i].x = parseFloat(this.points[i].x) * sx;
\t\t\t\tthis.points[i].y = parseFloat(this.points[i].y) * sy;
\t\t\t}
\t\t}
\t}
\t
\t// Translates the geometry
\tif (!this.relative)
\t{
\t\tthis.x = parseFloat(this.x) * sx;
\t\tthis.y = parseFloat(this.y) * sy;

\t\tif (fixedAspect)
\t\t{
\t\t\tsy = sx = Math.min(sx, sy);
\t\t}
\t\t
\t\tthis.width = parseFloat(this.width) * sx;
\t\tthis.height = parseFloat(this.height) * sy;
\t}
};

/**
 * Function: equals
 * 
 * Returns true if the given object equals this geometry.
 */
mxGeometry.prototype.equals = function(obj)
{
\treturn mxRectangle.prototype.equals.apply(this, arguments) &&
\t\tthis.relative == obj.relative &&
\t\t((this.sourcePoint == null && obj.sourcePoint == null) || (this.sourcePoint != null && this.sourcePoint.equals(obj.sourcePoint))) &&
\t\t((this.targetPoint == null && obj.targetPoint == null) || (this.targetPoint != null && this.targetPoint.equals(obj.targetPoint))) &&
\t\t((this.points == null && obj.points == null) || (this.points != null && mxUtils.equalPoints(this.points, obj.points))) &&
\t\t((this.alternateBounds == null && obj.alternateBounds == null) || (this.alternateBounds != null && this.alternateBounds.equals(obj.alternateBounds))) &&
\t\t((this.offset == null && obj.offset == null) || (this.offset != null && this.offset.equals(obj.offset)));
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxCellPath =
{

\t/**
\t * Class: mxCellPath
\t * 
\t * Implements a mechanism for temporary cell Ids.
\t * 
\t * Variable: PATH_SEPARATOR
\t * 
\t * Defines the separator between the path components. Default is \".\".
\t */
\tPATH_SEPARATOR: '.',
\t
\t/**
\t * Function: create
\t * 
\t * Creates the cell path for the given cell. The cell path is a
\t * concatenation of the indices of all ancestors on the (finite) path to
\t * the root, eg. \"0.0.0.1\".
\t * 
\t * Parameters:
\t * 
\t * cell - Cell whose path should be returned.
\t */
\tcreate: function(cell)
\t{
\t\tvar result = '';
\t\t
\t\tif (cell != null)
\t\t{
\t\t\tvar parent = cell.getParent();
\t\t\t
\t\t\twhile (parent != null)
\t\t\t{
\t\t\t\tvar index = parent.getIndex(cell);
\t\t\t\tresult = index + mxCellPath.PATH_SEPARATOR + result;
\t\t\t\t
\t\t\t\tcell = parent;
\t\t\t\tparent = cell.getParent();
\t\t\t}
\t\t}
\t\t
\t\t// Removes trailing separator
\t\tvar n = result.length;
\t\t
\t\tif (n > 1)
\t\t{
\t\t\tresult = result.substring(0, n - 1);
\t\t}
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: getParentPath
\t * 
\t * Returns the path for the parent of the cell represented by the given
\t * path. Returns null if the given path has no parent.
\t * 
\t * Parameters:
\t * 
\t * path - Path whose parent path should be returned.
\t */
\tgetParentPath: function(path)
\t{
\t\tif (path != null)
\t\t{
\t\t\tvar index = path.lastIndexOf(mxCellPath.PATH_SEPARATOR);

\t\t\tif (index >= 0)
\t\t\t{
\t\t\t\treturn path.substring(0, index);
\t\t\t}
\t\t\telse if (path.length > 0)
\t\t\t{
\t\t\t\treturn '';
\t\t\t}
\t\t}

\t\treturn null;
\t},

\t/**
\t * Function: resolve
\t * 
\t * Returns the cell for the specified cell path using the given root as the
\t * root of the path.
\t * 
\t * Parameters:
\t * 
\t * root - Root cell of the path to be resolved.
\t * path - String that defines the path.
\t */
\tresolve: function(root, path)
\t{
\t\tvar parent = root;
\t\t
\t\tif (path != null)
\t\t{
\t\t\tvar tokens = path.split(mxCellPath.PATH_SEPARATOR);
\t\t\t
\t\t\tfor (var i=0; i<tokens.length; i++)
\t\t\t{
\t\t\t\tparent = parent.getChildAt(parseInt(tokens[i]));
\t\t\t}
\t\t}
\t\t
\t\treturn parent;
\t},
\t
\t/**
\t * Function: compare
\t * 
\t * Compares the given cell paths and returns -1 if p1 is smaller, 0 if
\t * p1 is equal and 1 if p1 is greater than p2.
\t */
\tcompare: function(p1, p2)
\t{
\t\tvar min = Math.min(p1.length, p2.length);
\t\tvar comp = 0;
\t\t
\t\tfor (var i = 0; i < min; i++)
\t\t{
\t\t\tif (p1[i] != p2[i])
\t\t\t{
\t\t\t\tif (p1[i].length == 0 ||
\t\t\t\t\tp2[i].length == 0)
\t\t\t\t{
\t\t\t\t\tcomp = (p1[i] == p2[i]) ? 0 : ((p1[i] > p2[i]) ? 1 : -1);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar t1 = parseInt(p1[i]);
\t\t\t\t\tvar t2 = parseInt(p2[i]);
\t\t\t\t\t
\t\t\t\t\tcomp = (t1 == t2) ? 0 : ((t1 > t2) ? 1 : -1);
\t\t\t\t}
\t\t\t\t
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t\t
\t\t// Compares path length if both paths are equal to this point
\t\tif (comp == 0)
\t\t{
\t\t\tvar t1 = p1.length;
\t\t\tvar t2 = p2.length;
\t\t\t
\t\t\tif (t1 != t2)
\t\t\t{
\t\t\t\tcomp = (t1 > t2) ? 1 : -1;
\t\t\t}
\t\t}
\t\t
\t\treturn comp;
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxPerimeter =
{
\t/**
\t * Class: mxPerimeter
\t * 
\t * Provides various perimeter functions to be used in a style
\t * as the value of <mxConstants.STYLE_PERIMETER>. Perimeters for
\t * rectangle, circle, rhombus and triangle are available.
\t *
\t * Example:
\t * 
\t * (code)
\t * <add as=\"perimeter\">mxPerimeter.RectanglePerimeter</add>
\t * (end)
\t * 
\t * Or programmatically:
\t * 
\t * (code)
\t * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
\t * (end)
\t * 
\t * When adding new perimeter functions, it is recommended to use the 
\t * mxPerimeter-namespace as follows:
\t * 
\t * (code)
\t * mxPerimeter.CustomPerimeter = function (bounds, vertex, next, orthogonal)
\t * {
\t *   var x = 0; // Calculate x-coordinate
\t *   var y = 0; // Calculate y-coordainte
\t *   
\t *   return new mxPoint(x, y);
\t * }
\t * (end)
\t * 
\t * The new perimeter should then be registered in the <mxStyleRegistry> as follows:
\t * (code)
\t * mxStyleRegistry.putValue('customPerimeter', mxPerimeter.CustomPerimeter);
\t * (end)
\t * 
\t * The custom perimeter above can now be used in a specific vertex as follows:
\t * 
\t * (code)
\t * model.setStyle(vertex, 'perimeter=customPerimeter');
\t * (end)
\t * 
\t * Note that the key of the <mxStyleRegistry> entry for the function should
\t * be used in string values, unless <mxGraphView.allowEval> is true, in
\t * which case you can also use mxPerimeter.CustomPerimeter for the value in
\t * the cell style above.
\t * 
\t * Or it can be used for all vertices in the graph as follows:
\t * 
\t * (code)
\t * var style = graph.getStylesheet().getDefaultVertexStyle();
\t * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.CustomPerimeter;
\t * (end)
\t * 
\t * Note that the object can be used directly when programmatically setting
\t * the value, but the key in the <mxStyleRegistry> should be used when
\t * setting the value via a key, value pair in a cell style.
\t * 
\t * The parameters are explained in <RectanglePerimeter>.
\t * 
\t * Function: RectanglePerimeter
\t * 
\t * Describes a rectangular perimeter for the given bounds.
\t *
\t * Parameters:
\t * 
\t * bounds - <mxRectangle> that represents the absolute bounds of the
\t * vertex.
\t * vertex - <mxCellState> that represents the vertex.
\t * next - <mxPoint> that represents the nearest neighbour point on the
\t * given edge.
\t * orthogonal - Boolean that specifies if the orthogonal projection onto
\t * the perimeter should be returned. If this is false then the intersection
\t * of the perimeter and the line between the next and the center point is
\t * returned.
\t */
\tRectanglePerimeter: function (bounds, vertex, next, orthogonal)
\t{
\t\tvar cx = bounds.getCenterX();
\t\tvar cy = bounds.getCenterY();
\t\tvar dx = next.x - cx;
\t\tvar dy = next.y - cy;
\t\tvar alpha = Math.atan2(dy, dx);
\t\tvar p = new mxPoint(0, 0);
\t\tvar pi = Math.PI;
\t\tvar pi2 = Math.PI/2;
\t\tvar beta = pi2 - alpha;
\t\tvar t = Math.atan2(bounds.height, bounds.width);
\t\t
\t\tif (alpha < -pi + t || alpha > pi - t)
\t\t{
\t\t\t// Left edge
\t\t\tp.x = bounds.x;
\t\t\tp.y = cy - bounds.width * Math.tan(alpha) / 2;
\t\t}
\t\telse if (alpha < -t)
\t\t{
\t\t\t// Top Edge
\t\t\tp.y = bounds.y;
\t\t\tp.x = cx - bounds.height * Math.tan(beta) / 2;
\t\t}
\t\telse if (alpha < t)
\t\t{
\t\t\t// Right Edge
\t\t\tp.x = bounds.x + bounds.width;
\t\t\tp.y = cy + bounds.width * Math.tan(alpha) / 2;
\t\t}
\t\telse
\t\t{
\t\t\t// Bottom Edge
\t\t\tp.y = bounds.y + bounds.height;
\t\t\tp.x = cx + bounds.height * Math.tan(beta) / 2;
\t\t}
\t\t
\t\tif (orthogonal)
\t\t{
\t\t\tif (next.x >= bounds.x &&
\t\t\t\tnext.x <= bounds.x + bounds.width)
\t\t\t{
\t\t\t\tp.x = next.x;
\t\t\t}
\t\t\telse if (next.y >= bounds.y &&
\t\t\t\t\t   next.y <= bounds.y + bounds.height)
\t\t\t{
\t\t\t\tp.y = next.y;
\t\t\t}
\t\t\tif (next.x < bounds.x)
\t\t\t{
\t\t\t\tp.x = bounds.x;
\t\t\t}
\t\t\telse if (next.x > bounds.x + bounds.width)
\t\t\t{
\t\t\t\tp.x = bounds.x + bounds.width;
\t\t\t}
\t\t\tif (next.y < bounds.y)
\t\t\t{
\t\t\t\tp.y = bounds.y;
\t\t\t}
\t\t\telse if (next.y > bounds.y + bounds.height)
\t\t\t{
\t\t\t\tp.y = bounds.y + bounds.height;
\t\t\t}
\t\t}
\t\t
\t\treturn p;
\t},

\t/**
\t * Function: EllipsePerimeter
\t * 
\t * Describes an elliptic perimeter. See <RectanglePerimeter>
\t * for a description of the parameters.
\t */
\tEllipsePerimeter: function (bounds, vertex, next, orthogonal)
\t{
\t\tvar x = bounds.x;
\t\tvar y = bounds.y;
\t\tvar a = bounds.width / 2;
\t\tvar b = bounds.height / 2;
\t\tvar cx = x + a;
\t\tvar cy = y + b;
\t\tvar px = next.x;
\t\tvar py = next.y;
\t\t
\t\t// Calculates straight line equation through
\t\t// point and ellipse center y = d * x + h
\t\tvar dx = parseInt(px - cx);
\t\tvar dy = parseInt(py - cy);
\t\t
\t\tif (dx == 0 && dy != 0)
\t\t{
\t\t\treturn new mxPoint(cx, cy + b * dy / Math.abs(dy));
\t\t}
\t\telse if (dx == 0 && dy == 0)
\t\t{
\t\t\treturn new mxPoint(px, py);
\t\t}

\t\tif (orthogonal)
\t\t{
\t\t\tif (py >= y && py <= y + bounds.height)
\t\t\t{
\t\t\t\tvar ty = py - cy;
\t\t\t\tvar tx = Math.sqrt(a*a*(1-(ty*ty)/(b*b))) || 0;
\t\t\t\t
\t\t\t\tif (px <= x)
\t\t\t\t{
\t\t\t\t\ttx = -tx;
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn new mxPoint(cx+tx, py);
\t\t\t}
\t\t\t
\t\t\tif (px >= x && px <= x + bounds.width)
\t\t\t{
\t\t\t\tvar tx = px - cx;
\t\t\t\tvar ty = Math.sqrt(b*b*(1-(tx*tx)/(a*a))) || 0;
\t\t\t\t
\t\t\t\tif (py <= y)
\t\t\t\t{
\t\t\t\t\tty = -ty;\t
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn new mxPoint(px, cy+ty);
\t\t\t}
\t\t}
\t\t
\t\t// Calculates intersection
\t\tvar d = dy / dx;
\t\tvar h = cy - d * cx;
\t\tvar e = a * a * d * d + b * b;
\t\tvar f = -2 * cx * e;
\t\tvar g = a * a * d * d * cx * cx +
\t\t\t\tb * b * cx * cx -
\t\t\t\ta * a * b * b;
\t\tvar det = Math.sqrt(f * f - 4 * e * g);
\t\t
\t\t// Two solutions (perimeter points)
\t\tvar xout1 = (-f + det) / (2 * e);
\t\tvar xout2 = (-f - det) / (2 * e);
\t\tvar yout1 = d * xout1 + h;
\t\tvar yout2 = d * xout2 + h;
\t\tvar dist1 = Math.sqrt(Math.pow((xout1 - px), 2)
\t\t\t\t\t+ Math.pow((yout1 - py), 2));
\t\tvar dist2 = Math.sqrt(Math.pow((xout2 - px), 2)
\t\t\t\t\t+ Math.pow((yout2 - py), 2));
\t\t\t\t\t
\t\t// Correct solution
\t\tvar xout = 0;
\t\tvar yout = 0;
\t\t
\t\tif (dist1 < dist2)
\t\t{
\t\t\txout = xout1;
\t\t\tyout = yout1;
\t\t}
\t\telse
\t\t{
\t\t\txout = xout2;
\t\t\tyout = yout2;
\t\t}
\t\t
\t\treturn new mxPoint(xout, yout);
\t},

\t/**
\t * Function: RhombusPerimeter
\t * 
\t * Describes a rhombus (aka diamond) perimeter. See <RectanglePerimeter>
\t * for a description of the parameters.
\t */
\tRhombusPerimeter: function (bounds, vertex, next, orthogonal)
\t{
\t\tvar x = bounds.x;
\t\tvar y = bounds.y;
\t\tvar w = bounds.width;
\t\tvar h = bounds.height;
\t\t
\t\tvar cx = x + w / 2;
\t\tvar cy = y + h / 2;

\t\tvar px = next.x;
\t\tvar py = next.y;

\t\t// Special case for intersecting the diamond's corners
\t\tif (cx == px)
\t\t{
\t\t\tif (cy > py)
\t\t\t{
\t\t\t\treturn new mxPoint(cx, y); // top
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn new mxPoint(cx, y + h); // bottom
\t\t\t}
\t\t}
\t\telse if (cy == py)
\t\t{
\t\t\tif (cx > px)
\t\t\t{
\t\t\t\treturn new mxPoint(x, cy); // left
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn new mxPoint(x + w, cy); // right
\t\t\t}
\t\t}
\t\t
\t\tvar tx = cx;
\t\tvar ty = cy;
\t\t
\t\tif (orthogonal)
\t\t{
\t\t\tif (px >= x && px <= x + w)
\t\t\t{
\t\t\t\ttx = px;
\t\t\t}
\t\t\telse if (py >= y && py <= y + h)
\t\t\t{
\t\t\t\tty = py;
\t\t\t}
\t\t}
\t\t
\t\t// In which quadrant will the intersection be?
\t\t// set the slope and offset of the border line accordingly
\t\tif (px < cx)
\t\t{
\t\t\tif (py < cy)
\t\t\t{
\t\t\t\treturn mxUtils.intersection(px, py, tx, ty, cx, y, x, cy);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn mxUtils.intersection(px, py, tx, ty, cx, y + h, x, cy);
\t\t\t}
\t\t}
\t\telse if (py < cy)
\t\t{
\t\t\treturn mxUtils.intersection(px, py, tx, ty, cx, y, x + w, cy);
\t\t}
\t\telse
\t\t{
\t\t\treturn mxUtils.intersection(px, py, tx, ty, cx, y + h, x + w, cy);
\t\t}
\t},
\t
\t/**
\t * Function: TrianglePerimeter
\t * 
\t * Describes a triangle perimeter. See <RectanglePerimeter>
\t * for a description of the parameters.
\t */
\tTrianglePerimeter: function (bounds, vertex, next, orthogonal)
\t{
\t\tvar direction = (vertex != null) ?
\t\t\tvertex.style[mxConstants.STYLE_DIRECTION] : null;
\t\tvar vertical = direction == mxConstants.DIRECTION_NORTH ||
\t\t\tdirection == mxConstants.DIRECTION_SOUTH;

\t\tvar x = bounds.x;
\t\tvar y = bounds.y;
\t\tvar w = bounds.width;
\t\tvar h = bounds.height;
\t\t
\t\tvar cx = x + w / 2;
\t\tvar cy = y + h / 2;
\t\t
\t\tvar start = new mxPoint(x, y);
\t\tvar corner = new mxPoint(x + w, cy);
\t\tvar end = new mxPoint(x, y + h);
\t\t
\t\tif (direction == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\tstart = end;
\t\t\tcorner = new mxPoint(cx, y);
\t\t\tend = new mxPoint(x + w, y + h);
\t\t}
\t\telse if (direction == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\tcorner = new mxPoint(cx, y + h);
\t\t\tend = new mxPoint(x + w, y);
\t\t}
\t\telse if (direction == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tstart = new mxPoint(x + w, y);
\t\t\tcorner = new mxPoint(x, cy);
\t\t\tend = new mxPoint(x + w, y + h);
\t\t}

\t\tvar dx = next.x - cx;
\t\tvar dy = next.y - cy;

\t\tvar alpha = (vertical) ? Math.atan2(dx, dy) : Math.atan2(dy, dx);
\t\tvar t = (vertical) ? Math.atan2(w, h) : Math.atan2(h, w);
\t\t
\t\tvar base = false;
\t\t
\t\tif (direction == mxConstants.DIRECTION_NORTH ||
\t\t\tdirection == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tbase = alpha > -t && alpha < t;
\t\t}
\t\telse
\t\t{
\t\t\tbase = alpha < -Math.PI + t || alpha > Math.PI - t;\t
\t\t}

\t\tvar result = null;\t\t\t

\t\tif (base)
\t\t{
\t\t\tif (orthogonal && ((vertical && next.x >= start.x && next.x <= end.x) ||
\t\t\t\t(!vertical && next.y >= start.y && next.y <= end.y)))
\t\t\t{
\t\t\t\tif (vertical)
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(next.x, start.y);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(start.x, next.y);
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (direction == mxConstants.DIRECTION_NORTH)
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(x + w / 2 + h * Math.tan(alpha) / 2,
\t\t\t\t\t\ty + h);
\t\t\t\t}
\t\t\t\telse if (direction == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(x + w / 2 - h * Math.tan(alpha) / 2,
\t\t\t\t\t\ty);
\t\t\t\t}
\t\t\t\telse if (direction == mxConstants.DIRECTION_WEST)
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(x + w, y + h / 2 +
\t\t\t\t\t\tw * Math.tan(alpha) / 2);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tresult = new mxPoint(x, y + h / 2 -
\t\t\t\t\t\tw * Math.tan(alpha) / 2);
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (orthogonal)
\t\t\t{
\t\t\t\tvar pt = new mxPoint(cx, cy);
\t\t
\t\t\t\tif (next.y >= y && next.y <= y + h)
\t\t\t\t{
\t\t\t\t\tpt.x = (vertical) ? cx : (
\t\t\t\t\t\t(direction == mxConstants.DIRECTION_WEST) ?
\t\t\t\t\t\t\tx + w : x);
\t\t\t\t\tpt.y = next.y;
\t\t\t\t}
\t\t\t\telse if (next.x >= x && next.x <= x + w)
\t\t\t\t{
\t\t\t\t\tpt.x = next.x;
\t\t\t\t\tpt.y = (!vertical) ? cy : (
\t\t\t\t\t\t(direction == mxConstants.DIRECTION_NORTH) ?
\t\t\t\t\t\t\ty + h : y);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Compute angle
\t\t\t\tdx = next.x - pt.x;
\t\t\t\tdy = next.y - pt.y;
\t\t\t\t
\t\t\t\tcx = pt.x;
\t\t\t\tcy = pt.y;
\t\t\t}

\t\t\tif ((vertical && next.x <= x + w / 2) ||
\t\t\t\t(!vertical && next.y <= y + h / 2))
\t\t\t{
\t\t\t\tresult = mxUtils.intersection(next.x, next.y, cx, cy,
\t\t\t\t\tstart.x, start.y, corner.x, corner.y);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult = mxUtils.intersection(next.x, next.y, cx, cy,
\t\t\t\t\tcorner.x, corner.y, end.x, end.y);
\t\t\t}
\t\t}
\t\t
\t\tif (result == null)
\t\t{
\t\t\tresult = new mxPoint(cx, cy);
\t\t}
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: HexagonPerimeter
\t * 
\t * Describes a hexagon perimeter. See <RectanglePerimeter>
\t * for a description of the parameters.
\t */
\tHexagonPerimeter: function (bounds, vertex, next, orthogonal)
\t{
\t\tvar x = bounds.x;
\t\tvar y = bounds.y;
\t\tvar w = bounds.width;
\t\tvar h = bounds.height;

\t\tvar cx = bounds.getCenterX();
\t\tvar cy = bounds.getCenterY();
\t\tvar px = next.x;
\t\tvar py = next.y;
\t\tvar dx = px - cx;
\t\tvar dy = py - cy;
\t\tvar alpha = -Math.atan2(dy, dx);
\t\tvar pi = Math.PI;
\t\tvar pi2 = Math.PI / 2;

\t\tvar result = new mxPoint(cx, cy);

\t\tvar direction = (vertex != null) ? mxUtils.getValue(
\t\t\t\tvertex.style, mxConstants.STYLE_DIRECTION,
\t\t\t\tmxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
\t\tvar vertical = direction == mxConstants.DIRECTION_NORTH
\t\t\t\t|| direction == mxConstants.DIRECTION_SOUTH;
\t\tvar a = new mxPoint();
\t\tvar b = new mxPoint();

\t\t//Only consider corrects quadrants for the orthogonal case.
\t\tif ((px < x) && (py < y) || (px < x) && (py > y + h)
\t\t\t\t|| (px > x + w) && (py < y) || (px > x + w) && (py > y + h))
\t\t{
\t\t\torthogonal = false;
\t\t}

\t\tif (orthogonal)
\t\t{
\t\t\tif (vertical)
\t\t\t{
\t\t\t\t//Special cases where intersects with hexagon corners
\t\t\t\tif (px == cx)
\t\t\t\t{
\t\t\t\t\tif (py <= y)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(cx, y);
\t\t\t\t\t}
\t\t\t\t\telse if (py >= y + h)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(cx, y + h);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (px < x)
\t\t\t\t{
\t\t\t\t\tif (py == y + h / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x, y + h / 4);
\t\t\t\t\t}
\t\t\t\t\telse if (py == y + 3 * h / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x, y + 3 * h / 4);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (px > x + w)
\t\t\t\t{
\t\t\t\t\tif (py == y + h / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w, y + h / 4);
\t\t\t\t\t}
\t\t\t\t\telse if (py == y + 3 * h / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w, y + 3 * h / 4);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (px == x)
\t\t\t\t{
\t\t\t\t\tif (py < cy)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x, y + h / 4);
\t\t\t\t\t}
\t\t\t\t\telse if (py > cy)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x, y + 3 * h / 4);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (px == x + w)
\t\t\t\t{
\t\t\t\t\tif (py < cy)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w, y + h / 4);
\t\t\t\t\t}
\t\t\t\t\telse if (py > cy)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w, y + 3 * h / 4);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tif (py == y)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(cx, y);
\t\t\t\t}
\t\t\t\telse if (py == y + h)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(cx, y + h);
\t\t\t\t}

\t\t\t\tif (px < cx)
\t\t\t\t{
\t\t\t\t\tif ((py > y + h / 4) && (py < y + 3 * h / 4))
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x, y);
\t\t\t\t\t\tb = new mxPoint(x, y + h);
\t\t\t\t\t}
\t\t\t\t\telse if (py < y + h / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x - Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\t\tb = new mxPoint(x + w, y - Math.floor(0.25 * h));
\t\t\t\t\t}
\t\t\t\t\telse if (py > y + 3 * h / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x - Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\t\tb = new mxPoint(x + w, y + Math.floor(1.25 * h));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (px > cx)
\t\t\t\t{
\t\t\t\t\tif ((py > y + h / 4) && (py < y + 3 * h / 4))
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x + w, y);
\t\t\t\t\t\tb = new mxPoint(x + w, y + h);
\t\t\t\t\t}
\t\t\t\t\telse if (py < y + h / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x, y - Math.floor(0.25 * h));
\t\t\t\t\t\tb = new mxPoint(x + Math.floor(1.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\t}
\t\t\t\t\telse if (py > y + 3 * h / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x + Math.floor(1.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\t\tb = new mxPoint(x, y + Math.floor(1.25 * h));
\t\t\t\t\t}
\t\t\t\t}

\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t//Special cases where intersects with hexagon corners
\t\t\t\tif (py == cy)
\t\t\t\t{
\t\t\t\t\tif (px <= x)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x, y + h / 2);
\t\t\t\t\t}
\t\t\t\t\telse if (px >= x + w)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w, y + h / 2);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (py < y)
\t\t\t\t{
\t\t\t\t\tif (px == x + w / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w / 4, y);
\t\t\t\t\t}
\t\t\t\t\telse if (px == x + 3 * w / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + 3 * w / 4, y);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (py > y + h)
\t\t\t\t{
\t\t\t\t\tif (px == x + w / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w / 4, y + h);
\t\t\t\t\t}
\t\t\t\t\telse if (px == x + 3 * w / 4)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + 3 * w / 4, y + h);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (py == y)
\t\t\t\t{
\t\t\t\t\tif (px < cx)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w / 4, y);
\t\t\t\t\t}
\t\t\t\t\telse if (px > cx)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + 3 * w / 4, y);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (py == y + h)
\t\t\t\t{
\t\t\t\t\tif (px < cx)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + w / 4, y + h);
\t\t\t\t\t}
\t\t\t\t\telse if (py > cy)
\t\t\t\t\t{
\t\t\t\t\t\treturn new mxPoint(x + 3 * w / 4, y + h);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tif (px == x)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x, cy);
\t\t\t\t}
\t\t\t\telse if (px == x + w)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + w, cy);
\t\t\t\t}

\t\t\t\tif (py < cy)
\t\t\t\t{
\t\t\t\t\tif ((px > x + w / 4) && (px < x + 3 * w / 4))
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x, y);
\t\t\t\t\t\tb = new mxPoint(x + w, y);
\t\t\t\t\t}
\t\t\t\t\telse if (px < x + w / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x - Math.floor(0.25 * w), y + h);
\t\t\t\t\t\tb = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t- Math.floor(0.5 * h));
\t\t\t\t\t}
\t\t\t\t\telse if (px > x + 3 * w / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t- Math.floor(0.5 * h));
\t\t\t\t\t\tb = new mxPoint(x + Math.floor(1.25 * w), y + h);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (py > cy)
\t\t\t\t{
\t\t\t\t\tif ((px > x + w / 4) && (px < x + 3 * w / 4))
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x, y + h);
\t\t\t\t\t\tb = new mxPoint(x + w, y + h);
\t\t\t\t\t}
\t\t\t\t\telse if (px < x + w / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x - Math.floor(0.25 * w), y);
\t\t\t\t\t\tb = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(1.5 * h));
\t\t\t\t\t}
\t\t\t\t\telse if (px > x + 3 * w / 4)
\t\t\t\t\t{
\t\t\t\t\t\ta = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t\t+ Math.floor(1.5 * h));
\t\t\t\t\t\tb = new mxPoint(x + Math.floor(1.25 * w), y);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tvar tx = cx;
\t\t\tvar ty = cy;

\t\t\tif (px >= x && px <= x + w)
\t\t\t{
\t\t\t\ttx = px;
\t\t\t\t
\t\t\t\tif (py < cy)
\t\t\t\t{
\t\t\t\t\tty = y + h;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tty = y;
\t\t\t\t}
\t\t\t}
\t\t\telse if (py >= y && py <= y + h)
\t\t\t{
\t\t\t\tty = py;
\t\t\t\t
\t\t\t\tif (px < cx)
\t\t\t\t{
\t\t\t\t\ttx = x + w;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttx = x;
\t\t\t\t}
\t\t\t}

\t\t\tresult = mxUtils.intersection(tx, ty, next.x, next.y, a.x, a.y, b.x, b.y);
\t\t}
\t\telse
\t\t{
\t\t\tif (vertical)
\t\t\t{
\t\t\t\tvar beta = Math.atan2(h / 4, w / 2);

\t\t\t\t//Special cases where intersects with hexagon corners
\t\t\t\tif (alpha == beta)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + w, y + Math.floor(0.25 * h));
\t\t\t\t}
\t\t\t\telse if (alpha == pi2)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.5 * w), y);
\t\t\t\t}
\t\t\t\telse if (alpha == (pi - beta))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x, y + Math.floor(0.25 * h));
\t\t\t\t}
\t\t\t\telse if (alpha == -beta)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + w, y + Math.floor(0.75 * h));
\t\t\t\t}
\t\t\t\telse if (alpha == (-pi2))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.5 * w), y + h);
\t\t\t\t}
\t\t\t\telse if (alpha == (-pi + beta))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x, y + Math.floor(0.75 * h));
\t\t\t\t}

\t\t\t\tif ((alpha < beta) && (alpha > -beta))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x + w, y);
\t\t\t\t\tb = new mxPoint(x + w, y + h);
\t\t\t\t}
\t\t\t\telse if ((alpha > beta) && (alpha < pi2))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x, y - Math.floor(0.25 * h));
\t\t\t\t\tb = new mxPoint(x + Math.floor(1.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t}
\t\t\t\telse if ((alpha > pi2) && (alpha < (pi - beta)))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x - Math.floor(0.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\tb = new mxPoint(x + w, y - Math.floor(0.25 * h));
\t\t\t\t}
\t\t\t\telse if (((alpha > (pi - beta)) && (alpha <= pi))
\t\t\t\t\t\t|| ((alpha < (-pi + beta)) && (alpha >= -pi)))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x, y);
\t\t\t\t\tb = new mxPoint(x, y + h);
\t\t\t\t}
\t\t\t\telse if ((alpha < -beta) && (alpha > -pi2))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x + Math.floor(1.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\tb = new mxPoint(x, y + Math.floor(1.25 * h));
\t\t\t\t}
\t\t\t\telse if ((alpha < -pi2) && (alpha > (-pi + beta)))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x - Math.floor(0.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(0.5 * h));
\t\t\t\t\tb = new mxPoint(x + w, y + Math.floor(1.25 * h));
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar beta = Math.atan2(h / 2, w / 4);

\t\t\t\t//Special cases where intersects with hexagon corners
\t\t\t\tif (alpha == beta)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.75 * w), y);
\t\t\t\t}
\t\t\t\telse if (alpha == (pi - beta))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.25 * w), y);
\t\t\t\t}
\t\t\t\telse if ((alpha == pi) || (alpha == -pi))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x, y + Math.floor(0.5 * h));
\t\t\t\t}
\t\t\t\telse if (alpha == 0)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + w, y + Math.floor(0.5 * h));
\t\t\t\t}
\t\t\t\telse if (alpha == -beta)
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.75 * w), y + h);
\t\t\t\t}
\t\t\t\telse if (alpha == (-pi + beta))
\t\t\t\t{
\t\t\t\t\treturn new mxPoint(x + Math.floor(0.25 * w), y + h);
\t\t\t\t}

\t\t\t\tif ((alpha > 0) && (alpha < beta))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t- Math.floor(0.5 * h));
\t\t\t\t\tb = new mxPoint(x + Math.floor(1.25 * w), y + h);
\t\t\t\t}
\t\t\t\telse if ((alpha > beta) && (alpha < (pi - beta)))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x, y);
\t\t\t\t\tb = new mxPoint(x + w, y);
\t\t\t\t}
\t\t\t\telse if ((alpha > (pi - beta)) && (alpha < pi))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x - Math.floor(0.25 * w), y + h);
\t\t\t\t\tb = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t- Math.floor(0.5 * h));
\t\t\t\t}
\t\t\t\telse if ((alpha < 0) && (alpha > -beta))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(1.5 * h));
\t\t\t\t\tb = new mxPoint(x + Math.floor(1.25 * w), y);
\t\t\t\t}
\t\t\t\telse if ((alpha < -beta) && (alpha > (-pi + beta)))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x, y + h);
\t\t\t\t\tb = new mxPoint(x + w, y + h);
\t\t\t\t}
\t\t\t\telse if ((alpha < (-pi + beta)) && (alpha > -pi))
\t\t\t\t{
\t\t\t\t\ta = new mxPoint(x - Math.floor(0.25 * w), y);
\t\t\t\t\tb = new mxPoint(x + Math.floor(0.5 * w), y
\t\t\t\t\t\t\t+ Math.floor(1.5 * h));
\t\t\t\t}
\t\t\t}

\t\t\tresult = mxUtils.intersection(cx, cy, next.x, next.y, a.x, a.y, b.x, b.y);
\t\t}
\t\t
\t\tif (result == null)
\t\t{
\t\t\treturn new mxPoint(cx, cy);
\t\t}
\t\t
\t\treturn result;
\t}
};
/**
 * Copyright (c) 2006-2019, JGraph Ltd
 * Copyright (c) 2006-2017, draw.io AG
 */
/**
 * Class: mxPrintPreview
 * 
 * Implements printing of a diagram across multiple pages. The following opens
 * a print preview for an existing graph:
 * 
 * (code)
 * var preview = new mxPrintPreview(graph);
 * preview.open();
 * (end)
 * 
 * Use <mxUtils.getScaleForPageCount> as follows in order to print the graph
 * across a given number of pages:
 * 
 * (code)
 * var pageCount = mxUtils.prompt('Enter page count', '1');
 * 
 * if (pageCount != null)
 * {
 *   var scale = mxUtils.getScaleForPageCount(pageCount, graph);
 *   var preview = new mxPrintPreview(graph, scale);
 *   preview.open();
 * }
 * (end)
 * 
 * Additional pages:
 * 
 * To add additional pages before and after the output, <getCoverPages> and
 * <getAppendices> can be used, respectively.
 * 
 * (code)
 * var preview = new mxPrintPreview(graph, 1);
 * 
 * preview.getCoverPages = function(w, h)
 * {
 *   return [this.renderPage(w, h, 0, 0, mxUtils.bind(this, function(div)
 *   {
 *     div.innerHTML = '<div style=\"position:relative;margin:4px;\">Cover Page</p>'
 *   }))];
 * };
 * 
 * preview.getAppendices = function(w, h)
 * {
 *   return [this.renderPage(w, h, 0, 0, mxUtils.bind(this, function(div)
 *   {
 *     div.innerHTML = '<div style=\"position:relative;margin:4px;\">Appendix</p>'
 *   }))];
 * };
 * 
 * preview.open();
 * (end)
 * 
 * CSS:
 * 
 * The CSS from the original page is not carried over to the print preview.
 * To add CSS to the page, use the css argument in the <open> function or
 * override <writeHead> to add the respective link tags as follows:
 * 
 * (code)
 * var writeHead = preview.writeHead;
 * preview.writeHead = function(doc, css)
 * {
 *   writeHead.apply(this, arguments);
 *   doc.writeln('<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">');
 * };
 * (end)
 * 
 * Padding:
 * 
 * To add a padding to the page in the preview (but not the print output), use
 * the following code:
 * 
 * (code)
 * preview.writeHead = function(doc)
 * {
 *   writeHead.apply(this, arguments);
 *   
 *   doc.writeln('<style type=\"text/css\">');
 *   doc.writeln('@media screen {');
 *   doc.writeln('  body > div { padding-top:30px;padding-left:40px;box-sizing:content-box; }');
 *   doc.writeln('}');
 *   doc.writeln('</style>');
 * };
 * (end)
 * 
 * Headers:
 * 
 * Apart from setting the title argument in the mxPrintPreview constructor you
 * can override <renderPage> as follows to add a header to any page:
 * 
 * (code)
 * var oldRenderPage = mxPrintPreview.prototype.renderPage;
 * mxPrintPreview.prototype.renderPage = function(w, h, x, y, content, pageNumber)
 * {
 *   var div = oldRenderPage.apply(this, arguments);
 *   
 *   var header = document.createElement('div');
 *   header.style.position = 'absolute';
 *   header.style.top = '0px';
 *   header.style.width = '100%';
 *   header.style.textAlign = 'right';
 *   mxUtils.write(header, 'Your header here');
 *   div.firstChild.appendChild(header);
 *   
 *   return div;
 * };
 * (end)
 * 
 * The pageNumber argument contains the number of the current page, starting at
 * 1. To display a header on the first page only, check pageNumber and add a
 * vertical offset in the constructor call for the height of the header.
 * 
 * Page Format:
 * 
 * For landscape printing, use <mxConstants.PAGE_FORMAT_A4_LANDSCAPE> as
 * the pageFormat in <mxUtils.getScaleForPageCount> and <mxPrintPreview>.
 * Keep in mind that one can not set the defaults for the print dialog
 * of the operating system from JavaScript so the user must manually choose
 * a page format that matches this setting.
 * 
 * You can try passing the following CSS directive to <open> to set the
 * page format in the print dialog to landscape. However, this CSS
 * directive seems to be ignored in most major browsers, including IE.
 * 
 * (code)
 * @page {
 *   size: landscape;
 * }
 * (end)
 * 
 * Note that the print preview behaves differently in IE when used from the
 * filesystem or via HTTP so printing should always be tested via HTTP.
 * 
 * If you are using a DOCTYPE in the source page you can override <getDoctype>
 * and provide the same DOCTYPE for the print preview if required. Here is
 * an example for IE8 standards mode.
 * 
 * (code)
 * var preview = new mxPrintPreview(graph);
 * preview.getDoctype = function()
 * {
 *   return '<!--[if IE]><meta http-equiv=\"X-UA-Compatible\" content=\"IE=5,IE=8\" ><![endif]-->';
 * };
 * preview.open();
 * (end)
 * 
 * Constructor: mxPrintPreview
 *
 * Constructs a new print preview for the given parameters.
 * 
 * Parameters:
 * 
 * graph - <mxGraph> to be previewed.
 * scale - Optional scale of the output. Default is 1 / <mxGraph.pageScale>.
 * pageFormat - <mxRectangle> that specifies the page format (in pixels).
 * border - Border in pixels along each side of every page. Note that the
 * actual print function in the browser will add another border for
 * printing.
 * This should match the page format of the printer. Default uses the
 * <mxGraph.pageFormat> of the given graph.
 * x0 - Optional left offset of the output. Default is 0.
 * y0 - Optional top offset of the output. Default is 0.
 * borderColor - Optional color of the page border. Default is no border.
 * Note that a border is sometimes useful to highlight the printed page
 * border in the print preview of the browser.
 * title - Optional string that is used for the window title. Default
 * is 'Printer-friendly version'.
 * pageSelector - Optional boolean that specifies if the page selector
 * should appear in the window with the print preview. Default is true.
 */
function mxPrintPreview(graph, scale, pageFormat, border, x0, y0, borderColor, title, pageSelector)
{
\tthis.graph = graph;
\tthis.scale = (scale != null) ? scale : 1 / graph.pageScale;
\tthis.border = (border != null) ? border : 0;
\tthis.pageFormat = mxRectangle.fromRectangle((pageFormat != null) ? pageFormat : graph.pageFormat);
\tthis.title = (title != null) ? title : 'Printer-friendly version';
\tthis.x0 = (x0 != null) ? x0 : 0;
\tthis.y0 = (y0 != null) ? y0 : 0;
\tthis.borderColor = borderColor;
\tthis.pageSelector = (pageSelector != null) ? pageSelector : true;
};

/**
 * Variable: graph
 * 
 * Reference to the <mxGraph> that should be previewed.
 */
mxPrintPreview.prototype.graph = null;

/**
 * Variable: pageFormat
 *
 * Holds the <mxRectangle> that defines the page format.
 */
mxPrintPreview.prototype.pageFormat = null;

/**
 * Variable: scale
 * 
 * Holds the scale of the print preview.
 */
mxPrintPreview.prototype.scale = null;

/**
 * Variable: border
 * 
 * The border inset around each side of every page in the preview. This is set
 * to 0 if autoOrigin is false.
 */
mxPrintPreview.prototype.border = 0;

/**
 * Variable: marginTop
 * 
 * The margin at the top of the page (number). Default is 0.
 */
mxPrintPreview.prototype.marginTop = 0;

/**
 * Variable: marginBottom
 * 
 * The margin at the bottom of the page (number). Default is 0.
 */
mxPrintPreview.prototype.marginBottom = 0;

/**
 * Variable: x0
 * 
 * Holds the horizontal offset of the output.
 */
mxPrintPreview.prototype.x0 = 0;

/**
 * Variable: y0
 *
 * Holds the vertical offset of the output.
 */
mxPrintPreview.prototype.y0 = 0;

/**
 * Variable: autoOrigin
 * 
 * Specifies if the origin should be automatically computed based on the top,
 * left corner of the actual diagram contents. The required offset will be added
 * to <x0> and <y0> in <open>. Default is true.
 */
mxPrintPreview.prototype.autoOrigin = true;

/**
 * Variable: printOverlays
 * 
 * Specifies if overlays should be printed. Default is false.
 */
mxPrintPreview.prototype.printOverlays = false;

/**
 * Variable: printControls
 * 
 * Specifies if controls (such as folding icons) should be printed. Default is
 * false.
 */
mxPrintPreview.prototype.printControls = false;

/**
 * Variable: printBackgroundImage
 * 
 * Specifies if the background image should be printed. Default is false.
 */
mxPrintPreview.prototype.printBackgroundImage = false;

/**
 * Variable: backgroundColor
 * 
 * Holds the color value for the page background color. Default is #ffffff.
 */
mxPrintPreview.prototype.backgroundColor = '#ffffff';

/**
 * Variable: borderColor
 * 
 * Holds the color value for the page border.
 */
mxPrintPreview.prototype.borderColor = null;

/**
 * Variable: title
 * 
 * Holds the title of the preview window.
 */
mxPrintPreview.prototype.title = null;

/**
 * Variable: pageSelector
 * 
 * Boolean that specifies if the page selector should be
 * displayed. Default is true.
 */
mxPrintPreview.prototype.pageSelector = null;

/**
 * Variable: wnd
 * 
 * Reference to the preview window.
 */
mxPrintPreview.prototype.wnd = null;

/**
 * Variable: targetWindow
 * 
 * Assign any window here to redirect the rendering in <open>.
 */
mxPrintPreview.prototype.targetWindow = null;

/**
 * Variable: pageCount
 * 
 * Holds the actual number of pages in the preview.
 */
mxPrintPreview.prototype.pageCount = 0;

/**
 * Variable: clipping
 * 
 * Specifies is clipping should be used to avoid creating too many cell states
 * in large diagrams. The bounding box of the cells in the original diagram is
 * used if this is enabled. Default is true.
 */
mxPrintPreview.prototype.clipping = true;

/**
 * Function: getWindow
 * 
 * Returns <wnd>.
 */
mxPrintPreview.prototype.getWindow = function()
{
\treturn this.wnd;
};

/**
 * Function: getDocType
 * 
 * Returns the string that should go before the HTML tag in the print preview
 * page. This implementation returns an X-UA meta tag for IE5 in quirks mode,
 * IE8 in IE8 standards mode and edge in IE9 standards mode.
 */
mxPrintPreview.prototype.getDoctype = function()
{
\tvar dt = '';
\t
\tif (document.documentMode == 5)
\t{
\t\tdt = '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=5\">';
\t}
\telse if (document.documentMode == 8)
\t{
\t\tdt = '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\">';
\t}
\telse if (document.documentMode > 8)
\t{
\t\t// Comment needed to make standards doctype apply in IE
\t\tdt = '<!--[if IE]><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><![endif]-->';
\t}
\t
\treturn dt;
};

/**
 * Function: appendGraph
 * 
 * Adds the given graph to the existing print preview.
 * 
 * Parameters:
 * 
 * css - Optional CSS string to be used in the head section.
 * targetWindow - Optional window that should be used for rendering. If
 * this is specified then no HEAD tag, CSS and BODY tag will be written.
 */
mxPrintPreview.prototype.appendGraph = function(graph, scale, x0, y0, forcePageBreaks, keepOpen)
{
\tthis.graph = graph;
\tthis.scale = (scale != null) ? scale : 1 / graph.pageScale;
\tthis.x0 = x0;
\tthis.y0 = y0;
\tthis.open(null, null, forcePageBreaks, keepOpen);
};

/**
 * Function: open
 * 
 * Shows the print preview window. The window is created here if it does
 * not exist.
 * 
 * Parameters:
 * 
 * css - Optional CSS string to be used in the head section.
 * targetWindow - Optional window that should be used for rendering. If
 * this is specified then no HEAD tag, CSS and BODY tag will be written.
 */
mxPrintPreview.prototype.open = function(css, targetWindow, forcePageBreaks, keepOpen)
{
\t// Closing the window while the page is being rendered may cause an
\t// exception in IE. This and any other exceptions are simply ignored.
\tvar previousInitializeOverlay = this.graph.cellRenderer.initializeOverlay;
\tvar div = null;
\t
\ttry
\t{
\t\t// Temporarily overrides the method to redirect rendering of overlays
\t\t// to the draw pane so that they are visible in the printout
\t\tif (this.printOverlays)
\t\t{
\t\t\tthis.graph.cellRenderer.initializeOverlay = function(state, overlay)
\t\t\t{
\t\t\t\toverlay.init(state.view.getDrawPane());
\t\t\t};
\t\t}
\t\t
\t\tif (this.printControls)
\t\t{
\t\t\tthis.graph.cellRenderer.initControl = function(state, control, handleEvents, clickHandler)
\t\t\t{
\t\t\t\tcontrol.dialect = state.view.graph.dialect;
\t\t\t\tcontrol.init(state.view.getDrawPane());
\t\t\t};
\t\t}
\t\t
\t\tthis.wnd = (targetWindow != null) ? targetWindow : this.wnd;
\t\tvar isNewWindow = false;
\t\t
\t\tif (this.wnd == null)
\t\t{
\t\t\tisNewWindow = true;
\t\t\tthis.wnd = window.open();
\t\t}
\t\t
\t\tvar doc = this.wnd.document;
\t\t
\t\tif (isNewWindow)
\t\t{
\t\t\tvar dt = this.getDoctype();
\t\t\t
\t\t\tif (dt != null && dt.length > 0)
\t\t\t{
\t\t\t\tdoc.writeln(dt);
\t\t\t}
\t\t\t
\t\t\tif (mxClient.IS_VML)
\t\t\t{
\t\t\t\tdoc.writeln('<html xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">');
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (document.compatMode === 'CSS1Compat')
\t\t\t\t{
\t\t\t\t\tdoc.writeln('<!DOCTYPE html>');
\t\t\t\t}
\t\t\t\t
\t\t\t\tdoc.writeln('<html>');
\t\t\t}
\t\t\t
\t\t\tdoc.writeln('<head>');
\t\t\tthis.writeHead(doc, css);
\t\t\tdoc.writeln('</head>');
\t\t\tdoc.writeln('<body class=\"mxPage\">');
\t\t}

\t\t// Computes the horizontal and vertical page count
\t\tvar bounds = this.graph.getGraphBounds().clone();
\t\tvar currentScale = this.graph.getView().getScale();
\t\tvar sc = currentScale / this.scale;
\t\tvar tr = this.graph.getView().getTranslate();
\t\t
\t\t// Uses the absolute origin with no offset for all printing
\t\tif (!this.autoOrigin)
\t\t{
\t\t\tthis.x0 -= tr.x * this.scale;
\t\t\tthis.y0 -= tr.y * this.scale;
\t\t\tbounds.width += bounds.x;
\t\t\tbounds.height += bounds.y;
\t\t\tbounds.x = 0;
\t\t\tbounds.y = 0;
\t\t\tthis.border = 0;
\t\t}
\t\t
\t\t// Store the available page area
\t\tvar availableWidth = this.pageFormat.width - (this.border * 2);
\t\tvar availableHeight = this.pageFormat.height - (this.border * 2);
\t
\t\t// Adds margins to page format
\t\tthis.pageFormat.height += this.marginTop + this.marginBottom;

\t\t// Compute the unscaled, untranslated bounds to find
\t\t// the number of vertical and horizontal pages
\t\tbounds.width /= sc;
\t\tbounds.height /= sc;

\t\tvar hpages = Math.max(1, Math.ceil((bounds.width + this.x0) / availableWidth));
\t\tvar vpages = Math.max(1, Math.ceil((bounds.height + this.y0) / availableHeight));
\t\tthis.pageCount = hpages * vpages;
\t\t
\t\tvar writePageSelector = mxUtils.bind(this, function()
\t\t{
\t\t\tif (this.pageSelector && (vpages > 1 || hpages > 1))
\t\t\t{
\t\t\t\tvar table = this.createPageSelector(vpages, hpages);
\t\t\t\tdoc.body.appendChild(table);
\t\t\t\t
\t\t\t\t// Implements position: fixed in IE quirks mode
\t\t\t\tif (mxClient.IS_IE && doc.documentMode == null || doc.documentMode == 5 || doc.documentMode == 8 || doc.documentMode == 7)
\t\t\t\t{
\t\t\t\t\ttable.style.position = 'absolute';
\t\t\t\t\t
\t\t\t\t\tvar update = function()
\t\t\t\t\t{
\t\t\t\t\t\ttable.style.top = ((doc.body.scrollTop || doc.documentElement.scrollTop) + 10) + 'px';
\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\tmxEvent.addListener(this.wnd, 'scroll', function(evt)
\t\t\t\t\t{
\t\t\t\t\t\tupdate();
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tmxEvent.addListener(this.wnd, 'resize', function(evt)
\t\t\t\t\t{
\t\t\t\t\t\tupdate();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\tvar addPage = mxUtils.bind(this, function(div, addBreak)
\t\t{
\t\t\t// Border of the DIV (aka page) inside the document
\t\t\tif (this.borderColor != null)
\t\t\t{
\t\t\t\tdiv.style.borderColor = this.borderColor;
\t\t\t\tdiv.style.borderStyle = 'solid';
\t\t\t\tdiv.style.borderWidth = '1px';
\t\t\t}
\t\t\t
\t\t\t// Needs to be assigned directly because IE doesn't support
\t\t\t// child selectors, eg. body > div { background: white; }
\t\t\tdiv.style.background = this.backgroundColor;
\t\t\t
\t\t\tif (forcePageBreaks || addBreak)
\t\t\t{
\t\t\t\tdiv.style.pageBreakAfter = 'always';
\t\t\t}

\t\t\t// NOTE: We are dealing with cross-window DOM here, which
\t\t\t// is a problem in IE, so we copy the HTML markup instead.
\t\t\t// The underlying problem is that the graph display markup
\t\t\t// creation (in mxShape, mxGraphView) is hardwired to using
\t\t\t// document.createElement and hence we must use this document
\t\t\t// to create the complete page and then copy it over to the
\t\t\t// new window.document. This can be fixed later by using the
\t\t\t// ownerDocument of the container in mxShape and mxGraphView.
\t\t\tif (isNewWindow && (mxClient.IS_IE || document.documentMode >= 11 || mxClient.IS_EDGE))
\t\t\t{
\t\t\t\t// For some obscure reason, removing the DIV from the
\t\t\t\t// parent before fetching its outerHTML has missing
\t\t\t\t// fillcolor properties and fill children, so the div
\t\t\t\t// must be removed afterwards to keep the fillcolors.
\t\t\t\tdoc.writeln(div.outerHTML);
\t\t\t\tdiv.parentNode.removeChild(div);
\t\t\t}
\t\t\telse if (mxClient.IS_IE || document.documentMode >= 11 || mxClient.IS_EDGE)
\t\t\t{
\t\t\t\tvar clone = doc.createElement('div');
\t\t\t\tclone.innerHTML = div.outerHTML;
\t\t\t\tclone = clone.getElementsByTagName('div')[0];
\t\t\t\tdoc.body.appendChild(clone);
\t\t\t\tdiv.parentNode.removeChild(div);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdiv.parentNode.removeChild(div);
\t\t\t\tdoc.body.appendChild(div);
\t\t\t}

\t\t\tif (forcePageBreaks || addBreak)
\t\t\t{
\t\t\t\tthis.addPageBreak(doc);
\t\t\t}
\t\t});
\t\t
\t\tvar cov = this.getCoverPages(this.pageFormat.width, this.pageFormat.height);
\t\t
\t\tif (cov != null)
\t\t{
\t\t\tfor (var i = 0; i < cov.length; i++)
\t\t\t{
\t\t\t\taddPage(cov[i], true);
\t\t\t}
\t\t}
\t\t
\t\tvar apx = this.getAppendices(this.pageFormat.width, this.pageFormat.height);
\t\t
\t\t// Appends each page to the page output for printing, making
\t\t// sure there will be a page break after each page (ie. div)
\t\tfor (var i = 0; i < vpages; i++)
\t\t{
\t\t\tvar dy = i * availableHeight / this.scale - this.y0 / this.scale +
\t\t\t\t\t(bounds.y - tr.y * currentScale) / currentScale;
\t\t\t
\t\t\tfor (var j = 0; j < hpages; j++)
\t\t\t{
\t\t\t\tif (this.wnd == null)
\t\t\t\t{
\t\t\t\t\treturn null;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar dx = j * availableWidth / this.scale - this.x0 / this.scale +
\t\t\t\t\t\t(bounds.x - tr.x * currentScale) / currentScale;
\t\t\t\tvar pageNum = i * hpages + j + 1;
\t\t\t\tvar clip = new mxRectangle(dx, dy, availableWidth, availableHeight);
\t\t\t\tdiv = this.renderPage(this.pageFormat.width, this.pageFormat.height, 0, 0, mxUtils.bind(this, function(div)
\t\t\t\t{
\t\t\t\t\tthis.addGraphFragment(-dx, -dy, this.scale, pageNum, div, clip);
\t\t\t\t\t
\t\t\t\t\tif (this.printBackgroundImage)
\t\t\t\t\t{
\t\t\t\t\t\tthis.insertBackgroundImage(div, -dx, -dy);
\t\t\t\t\t}
\t\t\t\t}), pageNum);

\t\t\t\t// Gives the page a unique ID for later accessing the page
\t\t\t\tdiv.setAttribute('id', 'mxPage-'+pageNum);

\t\t\t\taddPage(div, apx != null || i < vpages - 1 || j < hpages - 1);
\t\t\t}
\t\t}

\t\tif (apx != null)
\t\t{
\t\t\tfor (var i = 0; i < apx.length; i++)
\t\t\t{
\t\t\t\taddPage(apx[i], i < apx.length - 1);
\t\t\t}
\t\t}

\t\tif (isNewWindow && !keepOpen)
\t\t{
\t\t\tthis.closeDocument();
\t\t\twritePageSelector();
\t\t}
\t\t
\t\tthis.wnd.focus();
\t}
\tcatch (e)
\t{
\t\t// Removes the DIV from the document in case of an error
\t\tif (div != null && div.parentNode != null)
\t\t{
\t\t\tdiv.parentNode.removeChild(div);
\t\t}
\t}
\tfinally
\t{
\t\tthis.graph.cellRenderer.initializeOverlay = previousInitializeOverlay;
\t}

\treturn this.wnd;
};

/**
 * Function: addPageBreak
 * 
 * Adds a page break to the given document.
 */
mxPrintPreview.prototype.addPageBreak = function(doc)
{
\tvar hr = doc.createElement('hr');
\thr.className = 'mxPageBreak';
\tdoc.body.appendChild(hr);
};

/**
 * Function: closeDocument
 * 
 * Writes the closing tags for body and page after calling <writePostfix>.
 */
mxPrintPreview.prototype.closeDocument = function()
{
\ttry
\t{
\t\tif (this.wnd != null && this.wnd.document != null)
\t\t{
\t\t\tvar doc = this.wnd.document;
\t\t\t
\t\t\tthis.writePostfix(doc);
\t\t\tdoc.writeln('</body>');
\t\t\tdoc.writeln('</html>');
\t\t\tdoc.close();
\t\t\t
\t\t\t// Removes all event handlers in the print output
\t\t\tmxEvent.release(doc.body);
\t\t}
\t}
\tcatch (e)
\t{
\t\t// ignore any errors resulting from wnd no longer being available
\t}
};

/**
 * Function: writeHead
 * 
 * Writes the HEAD section into the given document, without the opening
 * and closing HEAD tags.
 */
mxPrintPreview.prototype.writeHead = function(doc, css)
{
\tif (this.title != null)
\t{
\t\tdoc.writeln('<title>' + this.title + '</title>');
\t}
\t
\t// Adds required namespaces
\tif (mxClient.IS_VML)
\t{
\t\tdoc.writeln('<style type=\"text/css\">v\\\\:*{behavior:url(#default#VML)}o\\\\:*{behavior:url(#default#VML)}</style>');
\t}

\t// Adds all required stylesheets
\tmxClient.link('stylesheet', mxClient.basePath + '/css/common.css', doc);

\t// Removes horizontal rules and page selector from print output
\tdoc.writeln('<style type=\"text/css\">');
\tdoc.writeln('@media print {');
\tdoc.writeln('  * { -webkit-print-color-adjust: exact; }');
\tdoc.writeln('  table.mxPageSelector { display: none; }');
\tdoc.writeln('  hr.mxPageBreak { display: none; }');
\tdoc.writeln('}');
\tdoc.writeln('@media screen {');
\t
\t// NOTE: position: fixed is not supported in IE, so the page selector
\t// position (absolute) needs to be updated in IE (see below)
\tdoc.writeln('  table.mxPageSelector { position: fixed; right: 10px; top: 10px;' +
\t\t\t'font-family: Arial; font-size:10pt; border: solid 1px darkgray;' +
\t\t\t'background: white; border-collapse:collapse; }');
\tdoc.writeln('  table.mxPageSelector td { border: solid 1px gray; padding:4px; }');
\tdoc.writeln('  body.mxPage { background: gray; }');
\tdoc.writeln('}');
\t
\tif (css != null)
\t{
\t\tdoc.writeln(css);
\t}
\t
\tdoc.writeln('</style>');
};

/**
 * Function: writePostfix
 * 
 * Called before closing the body of the page. This implementation is empty.
 */
mxPrintPreview.prototype.writePostfix = function(doc)
{
\t// empty
};

/**
 * Function: createPageSelector
 * 
 * Creates the page selector table.
 */
mxPrintPreview.prototype.createPageSelector = function(vpages, hpages)
{
\tvar doc = this.wnd.document;
\tvar table = doc.createElement('table');
\ttable.className = 'mxPageSelector';
\ttable.setAttribute('border', '0');

\tvar tbody = doc.createElement('tbody');
\t
\tfor (var i = 0; i < vpages; i++)
\t{
\t\tvar row = doc.createElement('tr');
\t\t
\t\tfor (var j = 0; j < hpages; j++)
\t\t{
\t\t\tvar pageNum = i * hpages + j + 1;
\t\t\tvar cell = doc.createElement('td');
\t\t\tvar a = doc.createElement('a');
\t\t\ta.setAttribute('href', '#mxPage-' + pageNum);

\t\t\t// Workaround for FF where the anchor is appended to the URL of the original document
\t\t\tif (mxClient.IS_NS && !mxClient.IS_SF && !mxClient.IS_GC)
\t\t\t{
\t\t\t\tvar js = 'var page = document.getElementById(\\'mxPage-' + pageNum + '\\');page.scrollIntoView(true);event.preventDefault();';
\t\t\t\ta.setAttribute('onclick', js);
\t\t\t}
\t\t\t
\t\t\tmxUtils.write(a, pageNum, doc);
\t\t\tcell.appendChild(a);
\t\t\trow.appendChild(cell);
\t\t}
\t\t
\t\ttbody.appendChild(row);
\t}
\t
\ttable.appendChild(tbody);
\t
\treturn table;
};

/**
 * Function: renderPage
 * 
 * Creates a DIV that prints a single page of the given
 * graph using the given scale and returns the DIV that
 * represents the page.
 * 
 * Parameters:
 * 
 * w - Width of the page in pixels.
 * h - Height of the page in pixels.
 * dx - Optional horizontal page offset in pixels (used internally).
 * dy - Optional vertical page offset in pixels (used internally).
 * content - Callback that adds the HTML content to the inner div of a page.
 * Takes the inner div as the argument.
 * pageNumber - Integer representing the page number.
 */
mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, content, pageNumber)
{
\tvar doc = this.wnd.document;
\tvar div = document.createElement('div');
\tvar arg = null;

\ttry
\t{
\t\t// Workaround for ignored clipping in IE 9 standards
\t\t// when printing with page breaks and HTML labels.
\t\tif (dx != 0 || dy != 0)
\t\t{
\t\t\tdiv.style.position = 'relative';
\t\t\tdiv.style.width = w + 'px';
\t\t\tdiv.style.height = h + 'px';
\t\t\tdiv.style.pageBreakInside = 'avoid';
\t\t\t
\t\t\tvar innerDiv = document.createElement('div');
\t\t\tinnerDiv.style.position = 'relative';
\t\t\tinnerDiv.style.top = this.border + 'px';
\t\t\tinnerDiv.style.left = this.border + 'px';
\t\t\tinnerDiv.style.width = (w - 2 * this.border) + 'px';
\t\t\tinnerDiv.style.height = (h - 2 * this.border) + 'px';
\t\t\tinnerDiv.style.overflow = 'hidden';
\t\t\t
\t\t\tvar viewport = document.createElement('div');
\t\t\tviewport.style.position = 'relative';
\t\t\tviewport.style.marginLeft = dx + 'px';
\t\t\tviewport.style.marginTop = dy + 'px';

\t\t\t// FIXME: IE8 standards output problems
\t\t\tif (doc.documentMode == 8)
\t\t\t{
\t\t\t\tinnerDiv.style.position = 'absolute';
\t\t\t\tviewport.style.position = 'absolute';
\t\t\t}
\t\t
\t\t\tif (doc.documentMode == 10)
\t\t\t{
\t\t\t\tviewport.style.width = '100%';
\t\t\t\tviewport.style.height = '100%';
\t\t\t}
\t\t\t
\t\t\tinnerDiv.appendChild(viewport);
\t\t\tdiv.appendChild(innerDiv);
\t\t\tdocument.body.appendChild(div);
\t\t\targ = viewport;
\t\t}
\t\t// FIXME: IE10/11 too many pages
\t\telse
\t\t{
\t\t\tdiv.style.width = w + 'px';
\t\t\tdiv.style.height = h + 'px';
\t\t\tdiv.style.overflow = 'hidden';
\t\t\tdiv.style.pageBreakInside = 'avoid';
\t\t\t
\t\t\t// IE8 uses above branch currently
\t\t\tif (doc.documentMode == 8)
\t\t\t{
\t\t\t\tdiv.style.position = 'relative';
\t\t\t}
\t\t\t
\t\t\tvar innerDiv = document.createElement('div');
\t\t\tinnerDiv.style.width = (w - 2 * this.border) + 'px';
\t\t\tinnerDiv.style.height = (h - 2 * this.border) + 'px';
\t\t\tinnerDiv.style.overflow = 'hidden';

\t\t\tif (mxClient.IS_IE && (doc.documentMode == null || doc.documentMode == 5 ||
\t\t\t\tdoc.documentMode == 8 || doc.documentMode == 7))
\t\t\t{
\t\t\t\tinnerDiv.style.marginTop = this.border + 'px';
\t\t\t\tinnerDiv.style.marginLeft = this.border + 'px';\t
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tinnerDiv.style.top = this.border + 'px';
\t\t\t\tinnerDiv.style.left = this.border + 'px';
\t\t\t}
\t
\t\t\tif (this.graph.dialect == mxConstants.DIALECT_VML)
\t\t\t{
\t\t\t\tinnerDiv.style.position = 'absolute';
\t\t\t}

\t\t\tdiv.appendChild(innerDiv);
\t\t\tdocument.body.appendChild(div);
\t\t\targ = innerDiv;
\t\t}
\t}
\tcatch (e)
\t{
\t\tdiv.parentNode.removeChild(div);
\t\tdiv = null;
\t\t
\t\tthrow e;
\t}

\tcontent(arg);
\t 
\treturn div;
};

/**
 * Function: getRoot
 * 
 * Returns the root cell for painting the graph.
 */
mxPrintPreview.prototype.getRoot = function()
{
\tvar root = this.graph.view.currentRoot;
\t
\tif (root == null)
\t{
\t\troot = this.graph.getModel().getRoot();
\t}
\t
\treturn root;
};

/**
 * Function: useCssTransforms
 * 
 * Returns true if CSS transforms should be used for scaling content.
 * This returns true if foreignObject is supported and we're not in Safari
 * as it has clipping bugs for transformed CSS content with foreignObjects.
 */
mxPrintPreview.prototype.useCssTransforms = function()
{
\treturn !mxClient.NO_FO && !mxClient.IS_SF;
};

/**
 * Function: addGraphFragment
 * 
 * Adds a graph fragment to the given div.
 * 
 * Parameters:
 * 
 * dx - Horizontal translation for the diagram.
 * dy - Vertical translation for the diagram.
 * scale - Scale for the diagram.
 * pageNumber - Number of the page to be rendered.
 * div - Div that contains the output.
 * clip - Contains the clipping rectangle as an <mxRectangle>.
 */
mxPrintPreview.prototype.addGraphFragment = function(dx, dy, scale, pageNumber, div, clip)
{
\tvar view = this.graph.getView();
\tvar previousContainer = this.graph.container;
\tthis.graph.container = div;
\t
\tvar canvas = view.getCanvas();
\tvar backgroundPane = view.getBackgroundPane();
\tvar drawPane = view.getDrawPane();
\tvar overlayPane = view.getOverlayPane();
\tvar realScale = scale;

\tif (this.graph.dialect == mxConstants.DIALECT_SVG)
\t{
\t\tview.createSvg();
\t\t
\t\t// Uses CSS transform for scaling
\t\tif (this.useCssTransforms())
\t\t{
\t\t\tvar g = view.getDrawPane().parentNode;
\t\t\tvar prev = g.getAttribute('transform');
\t\t\tg.setAttribute('transformOrigin', '0 0');
\t\t\tg.setAttribute('transform', 'scale(' + scale + ',' + scale + ')' +
\t\t\t\t'translate(' + dx + ',' + dy + ')');
\t\t\t
\t\t\tscale = 1;
\t\t\tdx = 0;
\t\t\tdy = 0;
\t\t}
\t}
\telse if (this.graph.dialect == mxConstants.DIALECT_VML)
\t{
\t\tview.createVml();
\t}
\telse
\t{
\t\tview.createHtml();
\t}
\t
\t// Disables events on the view
\tvar eventsEnabled = view.isEventsEnabled();
\tview.setEventsEnabled(false);
\t
\t// Disables the graph to avoid cursors
\tvar graphEnabled = this.graph.isEnabled();
\tthis.graph.setEnabled(false);

\t// Resets the translation
\tvar translate = view.getTranslate();
\tview.translate = new mxPoint(dx, dy);
\t
\t// Redraws only states that intersect the clip
\tvar redraw = this.graph.cellRenderer.redraw;
\tvar states = view.states;
\tvar s = view.scale;

\t// Gets the transformed clip for intersection check below
\tif (this.clipping)
\t{
\t\tvar tempClip = new mxRectangle((clip.x + translate.x) * s, (clip.y + translate.y) * s,
\t\t\t\tclip.width * s / realScale, clip.height * s / realScale);

\t\t// Checks clipping rectangle for speedup
\t\t// Must create terminal states for edge clipping even if terminal outside of clip
\t\tthis.graph.cellRenderer.redraw = function(state, force, rendering)
\t\t{
\t\t\tif (state != null)
\t\t\t{
\t\t\t\t// Gets original state from graph to find bounding box
\t\t\t\tvar orig = states.get(state.cell);
\t\t\t\t
\t\t\t\tif (orig != null)
\t\t\t\t{
\t\t\t\t\tvar bbox = view.getBoundingBox(orig, false);
\t\t\t\t\t
\t\t\t\t\t// Stops rendering if outside clip for speedup but ignores
\t\t\t\t\t// edge labels where width and height is set to 0
\t\t\t\t\tif (bbox != null && bbox.width > 0 && bbox.height > 0 &&
\t\t\t\t\t\t!mxUtils.intersects(tempClip, bbox))
\t\t\t\t\t{
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tredraw.apply(this, arguments);
\t\t};
\t}
\t
\tvar temp = null;
\t
\ttry
\t{
\t\t// Creates the temporary cell states in the view and
\t\t// draws them onto the temporary DOM nodes in the view
\t\tvar cells = [this.getRoot()];
\t\ttemp = new mxTemporaryCellStates(view, scale, cells, null, mxUtils.bind(this, function(state)
\t\t{
\t\t\treturn this.getLinkForCellState(state);
\t\t}));
\t}
\tfinally
\t{
\t\t// Removes overlay pane with selection handles
\t\t// controls and icons from the print output
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\tview.overlayPane.innerHTML = '';
\t\t\tview.canvas.style.overflow = 'hidden';
\t\t\tview.canvas.style.position = 'relative';
\t\t\tview.canvas.style.top = this.marginTop + 'px';
\t\t\tview.canvas.style.width = clip.width + 'px';
\t\t\tview.canvas.style.height = clip.height + 'px';
\t\t}
\t\telse
\t\t{
\t\t\t// Removes everything but the SVG node
\t\t\tvar tmp = div.firstChild;

\t\t\twhile (tmp != null)
\t\t\t{
\t\t\t\tvar next = tmp.nextSibling;
\t\t\t\tvar name = tmp.nodeName.toLowerCase();

\t\t\t\t// Note: Width and height are required in FF 11
\t\t\t\tif (name == 'svg')
\t\t\t\t{
\t\t\t\t\ttmp.style.overflow = 'hidden';
\t\t\t\t\ttmp.style.position = 'relative';
\t\t\t\t\ttmp.style.top = this.marginTop + 'px';
\t\t\t\t\ttmp.setAttribute('width', clip.width);
\t\t\t\t\ttmp.setAttribute('height', clip.height);
\t\t\t\t\ttmp.style.width = '';
\t\t\t\t\ttmp.style.height = '';
\t\t\t\t}
\t\t\t\t// Tries to fetch all text labels and only text labels
\t\t\t\telse if (tmp.style.cursor != 'default' && name != 'div')
\t\t\t\t{
\t\t\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\t\t}
\t\t\t\t
\t\t\t\ttmp = next;
\t\t\t}
\t\t}
\t\t
\t\t// Puts background image behind SVG output
\t\tif (this.printBackgroundImage)
\t\t{
\t\t\tvar svgs = div.getElementsByTagName('svg');
\t\t\t
\t\t\tif (svgs.length > 0)
\t\t\t{
\t\t\t\tsvgs[0].style.position = 'absolute';
\t\t\t}
\t\t}
\t\t
\t\t// Completely removes the overlay pane to remove more handles
\t\tview.overlayPane.parentNode.removeChild(view.overlayPane);

\t\t// Restores the state of the view
\t\tthis.graph.setEnabled(graphEnabled);
\t\tthis.graph.container = previousContainer;
\t\tthis.graph.cellRenderer.redraw = redraw;
\t\tview.canvas = canvas;
\t\tview.backgroundPane = backgroundPane;
\t\tview.drawPane = drawPane;
\t\tview.overlayPane = overlayPane;
\t\tview.translate = translate;
\t\ttemp.destroy();
\t\tview.setEventsEnabled(eventsEnabled);
\t}
};

/**
 * Function: getLinkForCellState
 * 
 * Returns the link for the given cell state. This returns null.
 */
mxPrintPreview.prototype.getLinkForCellState = function(state)
{
\treturn this.graph.getLinkForCell(state.cell);
};

/**
 * Function: insertBackgroundImage
 * 
 * Inserts the background image into the given div.
 */
mxPrintPreview.prototype.insertBackgroundImage = function(div, dx, dy)
{
\tvar bg = this.graph.backgroundImage;
\t
\tif (bg != null)
\t{
\t\tvar img = document.createElement('img');
\t\timg.style.position = 'absolute';
\t\timg.style.marginLeft = Math.round(dx * this.scale) + 'px';
\t\timg.style.marginTop = Math.round(dy * this.scale) + 'px';
\t\timg.setAttribute('width', Math.round(this.scale * bg.width));
\t\timg.setAttribute('height', Math.round(this.scale * bg.height));
\t\timg.src = bg.src;
\t\t
\t\tdiv.insertBefore(img, div.firstChild);
\t}
};

/**
 * Function: getCoverPages
 * 
 * Returns the pages to be added before the print output. This returns null.
 */
mxPrintPreview.prototype.getCoverPages = function()
{
\treturn null;
};

/**
 * Function: getAppendices
 * 
 * Returns the pages to be added after the print output. This returns null.
 */
mxPrintPreview.prototype.getAppendices = function()
{
\treturn null;
};

/**
 * Function: print
 * 
 * Opens the print preview and shows the print dialog.
 * 
 * Parameters:
 * 
 * css - Optional CSS string to be used in the head section.
 */
mxPrintPreview.prototype.print = function(css)
{
\tvar wnd = this.open(css);
\t
\tif (wnd != null)
\t{
\t\twnd.print();
\t}
};

/**
 * Function: close
 * 
 * Closes the print preview window.
 */
mxPrintPreview.prototype.close = function()
{
\tif (this.wnd != null)
\t{
\t\tthis.wnd.close();
\t\tthis.wnd = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStylesheet
 *
 * Defines the appearance of the cells in a graph. See <putCellStyle> for an
 * example of creating a new cell style. It is recommended to use objects, not
 * arrays for holding cell styles. Existing styles can be cloned using
 * <mxUtils.clone> and turned into a string for debugging using
 * <mxUtils.toString>.
 *
 * Default Styles:
 *
 * The stylesheet contains two built-in styles, which are used if no style is
 * defined for a cell:
 *
 *   defaultVertex - Default style for vertices
 *   defaultEdge - Default style for edges
 *
 * Example:
 *
 * (code)
 * var vertexStyle = stylesheet.getDefaultVertexStyle();
 * vertexStyle[mxConstants.STYLE_ROUNDED] = true;
 * var edgeStyle = stylesheet.getDefaultEdgeStyle();
 * edgeStyle[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation;
 * (end)
 *
 * Modifies the built-in default styles.
 *
 * To avoid the default style for a cell, add a leading semicolon
 * to the style definition, eg.
 *
 * (code)
 * ;shadow=1
 * (end)
 *
 * Removing keys:
 *
 * For removing a key in a cell style of the form [stylename;|key=value;] the
 * special value none can be used, eg. highlight;fillColor=none
 *
 * See also the helper methods in mxUtils to modify strings of this format,
 * namely <mxUtils.setStyle>, <mxUtils.indexOfStylename>,
 * <mxUtils.addStylename>, <mxUtils.removeStylename>,
 * <mxUtils.removeAllStylenames> and <mxUtils.setStyleFlag>.
 *
 * Constructor: mxStylesheet
 *
 * Constructs a new stylesheet and assigns default styles.
 */
function mxStylesheet()
{
\tthis.styles = new Object();

\tthis.putDefaultVertexStyle(this.createDefaultVertexStyle());
\tthis.putDefaultEdgeStyle(this.createDefaultEdgeStyle());
};

/**
 * Function: styles
 *
 * Maps from names to cell styles. Each cell style is a map of key,
 * value pairs.
 */
mxStylesheet.prototype.styles;

/**
 * Function: createDefaultVertexStyle
 *
 * Creates and returns the default vertex style.
 */
mxStylesheet.prototype.createDefaultVertexStyle = function()
{
\tvar style = new Object();

\tstyle[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
\tstyle[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
\tstyle[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
\tstyle[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
\tstyle[mxConstants.STYLE_FILLCOLOR] = '#C3D9FF';
\tstyle[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
\tstyle[mxConstants.STYLE_FONTCOLOR] = '#774400';

\treturn style;
};

/**
 * Function: createDefaultEdgeStyle
 *
 * Creates and returns the default edge style.
 */
mxStylesheet.prototype.createDefaultEdgeStyle = function()
{
\tvar style = new Object();

\tstyle[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR;
\tstyle[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC;
\tstyle[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
\tstyle[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
\tstyle[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
\tstyle[mxConstants.STYLE_FONTCOLOR] = '#446299';

\treturn style;
};

/**
 * Function: putDefaultVertexStyle
 *
 * Sets the default style for vertices using defaultVertex as the
 * stylename.
 *
 * Parameters:
 * style - Key, value pairs that define the style.
 */
mxStylesheet.prototype.putDefaultVertexStyle = function(style)
{
\tthis.putCellStyle('defaultVertex', style);
};

/**
 * Function: putDefaultEdgeStyle
 *
 * Sets the default style for edges using defaultEdge as the stylename.
 */
mxStylesheet.prototype.putDefaultEdgeStyle = function(style)
{
\tthis.putCellStyle('defaultEdge', style);
};

/**
 * Function: getDefaultVertexStyle
 *
 * Returns the default style for vertices.
 */
mxStylesheet.prototype.getDefaultVertexStyle = function()
{
\treturn this.styles['defaultVertex'];
};

/**
 * Function: getDefaultEdgeStyle
 *
 * Sets the default style for edges.
 */
mxStylesheet.prototype.getDefaultEdgeStyle = function()
{
\treturn this.styles['defaultEdge'];
};

/**
 * Function: putCellStyle
 *
 * Stores the given map of key, value pairs under the given name in
 * <styles>.
 *
 * Example:
 *
 * The following example adds a new style called 'rounded' into an
 * existing stylesheet:
 *
 * (code)
 * var style = new Object();
 * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
 * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
 * style[mxConstants.STYLE_ROUNDED] = true;
 * graph.getStylesheet().putCellStyle('rounded', style);
 * (end)
 *
 * In the above example, the new style is an object. The possible keys of
 * the object are all the constants in <mxConstants> that start with STYLE
 * and the values are either JavaScript objects, such as
 * <mxPerimeter.RightAngleRectanglePerimeter> (which is in fact a function)
 * or expressions, such as true. Note that not all keys will be
 * interpreted by all shapes (eg. the line shape ignores the fill color).
 * The final call to this method associates the style with a name in the
 * stylesheet. The style is used in a cell with the following code:
 *
 * (code)
 * model.setStyle(cell, 'rounded');
 * (end)
 *
 * Parameters:
 *
 * name - Name for the style to be stored.
 * style - Key, value pairs that define the style.
 */
mxStylesheet.prototype.putCellStyle = function(name, style)
{
\tthis.styles[name] = style;
};

/**
 * Function: getCellStyle
 *
 * Returns the cell style for the specified stylename or the given
 * defaultStyle if no style can be found for the given stylename.
 *
 * Parameters:
 *
 * name - String of the form [(stylename|key=value);] that represents the
 * style.
 * defaultStyle - Default style to be returned if no style can be found.
 */
mxStylesheet.prototype.getCellStyle = function(name, defaultStyle)
{
\tvar style = defaultStyle;

\tif (name != null && name.length > 0)
\t{
\t\tvar pairs = name.split(';');

\t\tif (style != null &&
\t\t\tname.charAt(0) != ';')
\t\t{
\t\t\tstyle = mxUtils.clone(style);
\t\t}
\t\telse
\t\t{
\t\t\tstyle = new Object();
\t\t}

\t\t// Parses each key, value pair into the existing style
\t \tfor (var i = 0; i < pairs.length; i++)
\t \t{
\t \t\tvar tmp = pairs[i];
\t \t\tvar pos = tmp.indexOf('=');

\t \t\tif (pos >= 0)
\t \t\t{
\t\t \t\tvar key = tmp.substring(0, pos);
\t\t \t\tvar value = tmp.substring(pos + 1);

\t\t \t\tif (value == mxConstants.NONE)
\t\t \t\t{
\t\t \t\t\tdelete style[key];
\t\t \t\t}
\t\t \t\telse if (mxUtils.isNumeric(value))
\t\t \t\t{
\t\t \t\t\tstyle[key] = parseFloat(value);
\t\t \t\t}
\t\t \t\telse
\t\t \t\t{
\t\t\t \t\tstyle[key] = value;
\t\t \t\t}
\t\t\t}
\t \t\telse
\t \t\t{
\t \t\t\t// Merges the entries from a named style
\t\t\t\tvar tmpStyle = this.styles[tmp];

\t\t\t\tif (tmpStyle != null)
\t\t\t\t{
\t\t\t\t\tfor (var key in tmpStyle)
\t\t\t\t\t{
\t\t\t\t\t\tstyle[key] = tmpStyle[key];
\t\t\t\t\t}
\t\t\t\t}
\t \t\t}
\t\t}
\t}

\treturn style;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellState
 * 
 * Represents the current state of a cell in a given <mxGraphView>.
 * 
 * For edges, the edge label position is stored in <absoluteOffset>.
 * 
 * The size for oversize labels can be retrieved using the boundingBox property
 * of the <text> field as shown below.
 * 
 * (code)
 * var bbox = (state.text != null) ? state.text.boundingBox : null;
 * (end)
 * 
 * Constructor: mxCellState
 * 
 * Constructs a new object that represents the current state of the given
 * cell in the specified view.
 * 
 * Parameters:
 * 
 * view - <mxGraphView> that contains the state.
 * cell - <mxCell> that this state represents.
 * style - Array of key, value pairs that constitute the style.
 */
function mxCellState(view, cell, style)
{
\tthis.view = view;
\tthis.cell = cell;
\tthis.style = (style != null) ? style : {};
\t
\tthis.origin = new mxPoint();
\tthis.absoluteOffset = new mxPoint();
};

/**
 * Extends mxRectangle.
 */
mxCellState.prototype = new mxRectangle();
mxCellState.prototype.constructor = mxCellState;

/**
 * Variable: view
 * 
 * Reference to the enclosing <mxGraphView>.
 */
mxCellState.prototype.view = null;

/**
 * Variable: cell
 *
 * Reference to the <mxCell> that is represented by this state.
 */
mxCellState.prototype.cell = null;

/**
 * Variable: style
 * 
 * Contains an array of key, value pairs that represent the style of the
 * cell.
 */
mxCellState.prototype.style = null;

/**
 * Variable: invalidStyle
 * 
 * Specifies if the style is invalid. Default is false.
 */
mxCellState.prototype.invalidStyle = false;

/**
 * Variable: invalid
 * 
 * Specifies if the state is invalid. Default is true.
 */
mxCellState.prototype.invalid = true;

/**
 * Variable: origin
 *
 * <mxPoint> that holds the origin for all child cells. Default is a new
 * empty <mxPoint>.
 */
mxCellState.prototype.origin = null;

/**
 * Variable: absolutePoints
 * 
 * Holds an array of <mxPoints> that represent the absolute points of an
 * edge.
 */
mxCellState.prototype.absolutePoints = null;

/**
 * Variable: absoluteOffset
 *
 * <mxPoint> that holds the absolute offset. For edges, this is the
 * absolute coordinates of the label position. For vertices, this is the
 * offset of the label relative to the top, left corner of the vertex. 
 */
mxCellState.prototype.absoluteOffset = null;

/**
 * Variable: visibleSourceState
 * 
 * Caches the visible source terminal state.
 */
mxCellState.prototype.visibleSourceState = null;

/**
 * Variable: visibleTargetState
 * 
 * Caches the visible target terminal state.
 */
mxCellState.prototype.visibleTargetState = null;

/**
 * Variable: terminalDistance
 * 
 * Caches the distance between the end points for an edge.
 */
mxCellState.prototype.terminalDistance = 0;

/**
 * Variable: length
 *
 * Caches the length of an edge.
 */
mxCellState.prototype.length = 0;

/**
 * Variable: segments
 * 
 * Array of numbers that represent the cached length of each segment of the
 * edge.
 */
mxCellState.prototype.segments = null;

/**
 * Variable: shape
 * 
 * Holds the <mxShape> that represents the cell graphically.
 */
mxCellState.prototype.shape = null;

/**
 * Variable: text
 * 
 * Holds the <mxText> that represents the label of the cell. Thi smay be
 * null if the cell has no label.
 */
mxCellState.prototype.text = null;

/**
 * Variable: unscaledWidth
 * 
 * Holds the unscaled width of the state.
 */
mxCellState.prototype.unscaledWidth = null;

/**
 * Variable: unscaledHeight
 * 
 * Holds the unscaled height of the state.
 */
mxCellState.prototype.unscaledHeight = null;

/**
 * Function: getPerimeterBounds
 * 
 * Returns the <mxRectangle> that should be used as the perimeter of the
 * cell.
 * 
 * Parameters:
 * 
 * border - Optional border to be added around the perimeter bounds.
 * bounds - Optional <mxRectangle> to be used as the initial bounds.
 */
mxCellState.prototype.getPerimeterBounds = function(border, bounds)
{
\tborder = border || 0;
\tbounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height);
\t
\tif (this.shape != null && this.shape.stencil != null && this.shape.stencil.aspect == 'fixed')
\t{
\t\tvar aspect = this.shape.stencil.computeAspect(this.style, bounds.x, bounds.y, bounds.width, bounds.height);
\t\t
\t\tbounds.x = aspect.x;
\t\tbounds.y = aspect.y;
\t\tbounds.width = this.shape.stencil.w0 * aspect.width;
\t\tbounds.height = this.shape.stencil.h0 * aspect.height;
\t}
\t
\tif (border != 0)
\t{
\t\tbounds.grow(border);
\t}
\t
\treturn bounds;
};

/**
 * Function: setAbsoluteTerminalPoint
 * 
 * Sets the first or last point in <absolutePoints> depending on isSource.
 * 
 * Parameters:
 * 
 * point - <mxPoint> that represents the terminal point.
 * isSource - Boolean that specifies if the first or last point should
 * be assigned.
 */
mxCellState.prototype.setAbsoluteTerminalPoint = function(point, isSource)
{
\tif (isSource)
\t{
\t\tif (this.absolutePoints == null)
\t\t{
\t\t\tthis.absolutePoints = [];
\t\t}
\t\t
\t\tif (this.absolutePoints.length == 0)
\t\t{
\t\t\tthis.absolutePoints.push(point);
\t\t}
\t\telse
\t\t{
\t\t\tthis.absolutePoints[0] = point;
\t\t}
\t}
\telse
\t{
\t\tif (this.absolutePoints == null)
\t\t{
\t\t\tthis.absolutePoints = [];
\t\t\tthis.absolutePoints.push(null);
\t\t\tthis.absolutePoints.push(point);
\t\t}
\t\telse if (this.absolutePoints.length == 1)
\t\t{
\t\t\tthis.absolutePoints.push(point);
\t\t}
\t\telse
\t\t{
\t\t\tthis.absolutePoints[this.absolutePoints.length - 1] = point;
\t\t}
\t}
};

/**
 * Function: setCursor
 * 
 * Sets the given cursor on the shape and text shape.
 */
mxCellState.prototype.setCursor = function(cursor)
{
\tif (this.shape != null)
\t{
\t\tthis.shape.setCursor(cursor);
\t}
\t
\tif (this.text != null)
\t{
\t\tthis.text.setCursor(cursor);
\t}
};

/**
 * Function: getVisibleTerminal
 * 
 * Returns the visible source or target terminal cell.
 * 
 * Parameters:
 * 
 * source - Boolean that specifies if the source or target cell should be
 * returned.
 */
mxCellState.prototype.getVisibleTerminal = function(source)
{
\tvar tmp = this.getVisibleTerminalState(source);
\t
\treturn (tmp != null) ? tmp.cell : null;
};

/**
 * Function: getVisibleTerminalState
 * 
 * Returns the visible source or target terminal state.
 * 
 * Parameters:
 * 
 * source - Boolean that specifies if the source or target state should be
 * returned.
 */
mxCellState.prototype.getVisibleTerminalState = function(source)
{
\treturn (source) ? this.visibleSourceState : this.visibleTargetState;
};

/**
 * Function: setVisibleTerminalState
 * 
 * Sets the visible source or target terminal state.
 * 
 * Parameters:
 * 
 * terminalState - <mxCellState> that represents the terminal.
 * source - Boolean that specifies if the source or target state should be set.
 */
mxCellState.prototype.setVisibleTerminalState = function(terminalState, source)
{
\tif (source)
\t{
\t\tthis.visibleSourceState = terminalState;
\t}
\telse
\t{
\t\tthis.visibleTargetState = terminalState;
\t}
};

/**
 * Function: getCellBounds
 * 
 * Returns the unscaled, untranslated bounds.
 */
mxCellState.prototype.getCellBounds = function()
{
\treturn this.cellBounds;
};

/**
 * Function: getPaintBounds
 * 
 * Returns the unscaled, untranslated paint bounds. This is the same as
 * <getCellBounds> but with a 90 degree rotation if the shape's
 * isPaintBoundsInverted returns true.
 */
mxCellState.prototype.getPaintBounds = function()
{
\treturn this.paintBounds;
};

/**
 * Function: updateCachedBounds
 * 
 * Updates the cellBounds and paintBounds.
 */
mxCellState.prototype.updateCachedBounds = function()
{
\tvar tr = this.view.translate;
\tvar s = this.view.scale;
\tthis.cellBounds = new mxRectangle(this.x / s - tr.x, this.y / s - tr.y, this.width / s, this.height / s);
\tthis.paintBounds = mxRectangle.fromRectangle(this.cellBounds);
\t
\tif (this.shape != null && this.shape.isPaintBoundsInverted())
\t{
\t\tthis.paintBounds.rotate90();
\t}
};

/**
 * Destructor: setState
 * 
 * Copies all fields from the given state to this state.
 */
mxCellState.prototype.setState = function(state)
{
\tthis.view = state.view;
\tthis.cell = state.cell;
\tthis.style = state.style;
\tthis.absolutePoints = state.absolutePoints;
\tthis.origin = state.origin;
\tthis.absoluteOffset = state.absoluteOffset;
\tthis.boundingBox = state.boundingBox;
\tthis.terminalDistance = state.terminalDistance;
\tthis.segments = state.segments;
\tthis.length = state.length;
\tthis.x = state.x;
\tthis.y = state.y;
\tthis.width = state.width;
\tthis.height = state.height;
\tthis.unscaledWidth = state.unscaledWidth;
\tthis.unscaledHeight = state.unscaledHeight;
};

/**
 * Function: clone
 *
 * Returns a clone of this <mxPoint>.
 */
mxCellState.prototype.clone = function()
{
 \tvar clone = new mxCellState(this.view, this.cell, this.style);

\t// Clones the absolute points
\tif (this.absolutePoints != null)
\t{
\t\tclone.absolutePoints = [];
\t\t
\t\tfor (var i = 0; i < this.absolutePoints.length; i++)
\t\t{
\t\t\tclone.absolutePoints[i] = this.absolutePoints[i].clone();
\t\t}
\t}

\tif (this.origin != null)
\t{
\t\tclone.origin = this.origin.clone();
\t}

\tif (this.absoluteOffset != null)
\t{
\t\tclone.absoluteOffset = this.absoluteOffset.clone();
\t}

\tif (this.boundingBox != null)
\t{
\t\tclone.boundingBox = this.boundingBox.clone();
\t}

\tclone.terminalDistance = this.terminalDistance;
\tclone.segments = this.segments;
\tclone.length = this.length;
\tclone.x = this.x;
\tclone.y = this.y;
\tclone.width = this.width;
\tclone.height = this.height;
\tclone.unscaledWidth = this.unscaledWidth;
\tclone.unscaledHeight = this.unscaledHeight;
\t
\treturn clone;
};

/**
 * Destructor: destroy
 * 
 * Destroys the state and all associated resources.
 */
mxCellState.prototype.destroy = function()
{
\tthis.view.graph.cellRenderer.destroy(this);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphSelectionModel
 *
 * Implements the selection model for a graph. Here is a listener that handles
 * all removed selection cells.
 * 
 * (code)
 * graph.getSelectionModel().addListener(mxEvent.CHANGE, function(sender, evt)
 * {
 *   var cells = evt.getProperty('added');
 *   
 *   for (var i = 0; i < cells.length; i++)
 *   {
 *     // Handle cells[i]...
 *   }
 * });
 * (end)
 * 
 * Event: mxEvent.UNDO
 * 
 * Fires after the selection was changed in <changeSelection>. The
 * <code>edit</code> property contains the <mxUndoableEdit> which contains the
 * <mxSelectionChange>.
 * 
 * Event: mxEvent.CHANGE
 * 
 * Fires after the selection changes by executing an <mxSelectionChange>. The
 * <code>added</code> and <code>removed</code> properties contain arrays of
 * cells that have been added to or removed from the selection, respectively.
 * The names are inverted due to historic reasons. This cannot be changed.
 * 
 * Constructor: mxGraphSelectionModel
 *
 * Constructs a new graph selection model for the given <mxGraph>.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxGraphSelectionModel(graph)
{
\tthis.graph = graph;
\tthis.cells = [];
};

/**
 * Extends mxEventSource.
 */
mxGraphSelectionModel.prototype = new mxEventSource();
mxGraphSelectionModel.prototype.constructor = mxGraphSelectionModel;

/**
 * Variable: doneResource
 * 
 * Specifies the resource key for the status message after a long operation.
 * If the resource for this key does not exist then the value is used as
 * the status message. Default is 'done'.
 */
mxGraphSelectionModel.prototype.doneResource = (mxClient.language != 'none') ? 'done' : '';

/**
 * Variable: updatingSelectionResource
 *
 * Specifies the resource key for the status message while the selection is
 * being updated. If the resource for this key does not exist then the
 * value is used as the status message. Default is 'updatingSelection'.
 */
mxGraphSelectionModel.prototype.updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : '';

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxGraphSelectionModel.prototype.graph = null;

/**
 * Variable: singleSelection
 *
 * Specifies if only one selected item at a time is allowed.
 * Default is false.
 */
mxGraphSelectionModel.prototype.singleSelection = false;

/**
 * Function: isSingleSelection
 *
 * Returns <singleSelection> as a boolean.
 */
mxGraphSelectionModel.prototype.isSingleSelection = function()
{
\treturn this.singleSelection;
};

/**
 * Function: setSingleSelection
 *
 * Sets the <singleSelection> flag.
 * 
 * Parameters:
 * 
 * singleSelection - Boolean that specifies the new value for
 * <singleSelection>.
 */
mxGraphSelectionModel.prototype.setSingleSelection = function(singleSelection)
{
\tthis.singleSelection = singleSelection;
};

/**
 * Function: isSelected
 *
 * Returns true if the given <mxCell> is selected.
 */
mxGraphSelectionModel.prototype.isSelected = function(cell)
{
\tif (cell != null)
\t{
\t\treturn mxUtils.indexOf(this.cells, cell) >= 0;
\t}
\t
\treturn false;
};

/**
 * Function: isEmpty
 *
 * Returns true if no cells are currently selected.
 */
mxGraphSelectionModel.prototype.isEmpty = function()
{
\treturn this.cells.length == 0;
};

/**
 * Function: clear
 *
 * Clears the selection and fires a <change> event if the selection was not
 * empty.
 */
mxGraphSelectionModel.prototype.clear = function()
{
\tthis.changeSelection(null, this.cells);
};

/**
 * Function: setCell
 *
 * Selects the specified <mxCell> using <setCells>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be selected.
 */
mxGraphSelectionModel.prototype.setCell = function(cell)
{
\tif (cell != null)
\t{
\t\tthis.setCells([cell]);
\t}
};

/**
 * Function: setCells
 *
 * Selects the given array of <mxCells> and fires a <change> event.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be selected.
 */
mxGraphSelectionModel.prototype.setCells = function(cells)
{
\tif (cells != null)
\t{
\t\tif (this.singleSelection)
\t\t{
\t\t\tcells = [this.getFirstSelectableCell(cells)];
\t\t}
\t
\t\tvar tmp = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (this.graph.isCellSelectable(cells[i]))
\t\t\t{
\t\t\t\ttmp.push(cells[i]);
\t\t\t}\t
\t\t}

\t\tthis.changeSelection(tmp, this.cells);
\t}
};

/**
 * Function: getFirstSelectableCell
 *
 * Returns the first selectable cell in the given array of cells.
 */
mxGraphSelectionModel.prototype.getFirstSelectableCell = function(cells)
{
\tif (cells != null)
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (this.graph.isCellSelectable(cells[i]))
\t\t\t{
\t\t\t\treturn cells[i];
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: addCell
 * 
 * Adds the given <mxCell> to the selection and fires a <select> event.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to add to the selection.
 */
mxGraphSelectionModel.prototype.addCell = function(cell)
{
\tif (cell != null)
\t{
\t\tthis.addCells([cell]);
\t}
};

/**
 * Function: addCells
 * 
 * Adds the given array of <mxCells> to the selection and fires a <select>
 * event.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to add to the selection.
 */
mxGraphSelectionModel.prototype.addCells = function(cells)
{
\tif (cells != null)
\t{
\t\tvar remove = null;
\t\t
\t\tif (this.singleSelection)
\t\t{
\t\t\tremove = this.cells;
\t\t\tcells = [this.getFirstSelectableCell(cells)];
\t\t}

\t\tvar tmp = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (!this.isSelected(cells[i]) &&
\t\t\t\tthis.graph.isCellSelectable(cells[i]))
\t\t\t{
\t\t\t\ttmp.push(cells[i]);
\t\t\t}\t
\t\t}

\t\tthis.changeSelection(tmp, remove);
\t}
};

/**
 * Function: removeCell
 *
 * Removes the specified <mxCell> from the selection and fires a <select>
 * event for the remaining cells.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to remove from the selection.
 */
mxGraphSelectionModel.prototype.removeCell = function(cell)
{
\tif (cell != null)
\t{
\t\tthis.removeCells([cell]);
\t}
};

/**
 * Function: removeCells
 */
mxGraphSelectionModel.prototype.removeCells = function(cells)
{
\tif (cells != null)
\t{
\t\tvar tmp = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (this.isSelected(cells[i]))
\t\t\t{
\t\t\t\ttmp.push(cells[i]);
\t\t\t}
\t\t}
\t\t
\t\tthis.changeSelection(null, tmp);\t
\t}
};

/**
 * Function: changeSelection
 *
 * Adds/removes the specified arrays of <mxCell> to/from the selection.
 * 
 * Parameters:
 * 
 * added - Array of <mxCell> to add to the selection.
 * remove - Array of <mxCell> to remove from the selection.
 */
mxGraphSelectionModel.prototype.changeSelection = function(added, removed)
{
\tif ((added != null &&
\t\tadded.length > 0 &&
\t\tadded[0] != null) ||
\t\t(removed != null &&
\t\tremoved.length > 0 &&
\t\tremoved[0] != null))
\t{
\t\tvar change = new mxSelectionChange(this, added, removed);
\t\tchange.execute();
\t\tvar edit = new mxUndoableEdit(this, false);
\t\tedit.add(change);
\t\tthis.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
\t}
};

/**
 * Function: cellAdded
 *
 * Inner callback to add the specified <mxCell> to the selection. No event
 * is fired in this implementation.
 * 
 * Paramters:
 * 
 * cell - <mxCell> to add to the selection.
 */
mxGraphSelectionModel.prototype.cellAdded = function(cell)
{
\tif (cell != null &&
\t\t!this.isSelected(cell))
\t{
\t\tthis.cells.push(cell);
\t}
};

/**
 * Function: cellRemoved
 *
 * Inner callback to remove the specified <mxCell> from the selection. No
 * event is fired in this implementation.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to remove from the selection.
 */
mxGraphSelectionModel.prototype.cellRemoved = function(cell)
{
\tif (cell != null)
\t{
\t\tvar index = mxUtils.indexOf(this.cells, cell);
\t\t
\t\tif (index >= 0)
\t\t{
\t\t\tthis.cells.splice(index, 1);
\t\t}
\t}
};

/**
 * Class: mxSelectionChange
 *
 * Action to change the current root in a view.
 *
 * Constructor: mxCurrentRootChange
 *
 * Constructs a change of the current root in the given view.
 */
function mxSelectionChange(selectionModel, added, removed)
{
\tthis.selectionModel = selectionModel;
\tthis.added = (added != null) ? added.slice() : null;
\tthis.removed = (removed != null) ? removed.slice() : null;
};

/**
 * Function: execute
 *
 * Changes the current root of the view.
 */
mxSelectionChange.prototype.execute = function()
{
\tvar t0 = mxLog.enter('mxSelectionChange.execute');
\twindow.status = mxResources.get(
\t\tthis.selectionModel.updatingSelectionResource) ||
\t\tthis.selectionModel.updatingSelectionResource;

\tif (this.removed != null)
\t{
\t\tfor (var i = 0; i < this.removed.length; i++)
\t\t{
\t\t\tthis.selectionModel.cellRemoved(this.removed[i]);
\t\t}
\t}

\tif (this.added != null)
\t{
\t\tfor (var i = 0; i < this.added.length; i++)
\t\t{
\t\t\tthis.selectionModel.cellAdded(this.added[i]);
\t\t}
\t}
\t
\tvar tmp = this.added;
\tthis.added = this.removed;
\tthis.removed = tmp;

\twindow.status = mxResources.get(this.selectionModel.doneResource) ||
\t\tthis.selectionModel.doneResource;
\tmxLog.leave('mxSelectionChange.execute', t0);
\t
\tthis.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE,
\t\t\t'added', this.added, 'removed', this.removed));
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellEditor
 *
 * In-place editor for the graph. To control this editor, use
 * <mxGraph.invokesStopCellEditing>, <mxGraph.enterStopsCellEditing> and
 * <mxGraph.escapeEnabled>. If <mxGraph.enterStopsCellEditing> is true then
 * ctrl-enter or shift-enter can be used to create a linefeed. The F2 and
 * escape keys can always be used to stop editing.
 * 
 * To customize the location of the textbox in the graph, override
 * <getEditorBounds> as follows:
 * 
 * (code)
 * graph.cellEditor.getEditorBounds = function(state)
 * {
 *   var result = mxCellEditor.prototype.getEditorBounds.apply(this, arguments);
 *   
 *   if (this.graph.getModel().isEdge(state.cell))
 *   {
 *     result.x = state.getCenterX() - result.width / 2;
 *     result.y = state.getCenterY() - result.height / 2;
 *   }
 *   
 *   return result;
 * };
 * (end)
 * 
 * Note that this hook is only called if <autoSize> is false. If <autoSize> is true,
 * then <mxShape.getLabelBounds> is used to compute the current bounds of the textbox.
 * 
 * The textarea uses the mxCellEditor CSS class. You can modify this class in
 * your custom CSS. Note: You should modify the CSS after loading the client
 * in the page.
 *
 * Example:
 * 
 * To only allow numeric input in the in-place editor, use the following code.
 *
 * (code)
 * var text = graph.cellEditor.textarea;
 * 
 * mxEvent.addListener(text, 'keydown', function (evt)
 * {
 *   if (!(evt.keyCode >= 48 && evt.keyCode <= 57) &&
 *       !(evt.keyCode >= 96 && evt.keyCode <= 105))
 *   {
 *     mxEvent.consume(evt);
 *   }
 * }); 
 * (end)
 * 
 * Placeholder:
 * 
 * To implement a placeholder for cells without a label, use the
 * <emptyLabelText> variable.
 * 
 * Resize in Chrome:
 * 
 * Resize of the textarea is disabled by default. If you want to enable
 * this feature extend <init> and set this.textarea.style.resize = ''.
 * 
 * To start editing on a key press event, the container of the graph
 * should have focus or a focusable parent should be used to add the
 * key press handler as follows.
 * 
 * (code)
 * mxEvent.addListener(graph.container, 'keypress', mxUtils.bind(this, function(evt)
 * {
 *   if (!graph.isEditing() && !graph.isSelectionEmpty() && evt.which !== 0 &&
 *       !mxEvent.isAltDown(evt) && !mxEvent.isControlDown(evt) && !mxEvent.isMetaDown(evt))
 *   {
 *     graph.startEditing();
 *     
 *     if (mxClient.IS_FF)
 *     {
 *       graph.cellEditor.textarea.value = String.fromCharCode(evt.which);
 *     }
 *   }
 * }));
 * (end)
 * 
 * To allow focus for a DIV, and hence to receive key press events, some browsers
 * require it to have a valid tabindex attribute. In this case the following
 * code may be used to keep the container focused.
 * 
 * (code)
 * var graphFireMouseEvent = graph.fireMouseEvent;
 * graph.fireMouseEvent = function(evtName, me, sender)
 * {
 *   if (evtName == mxEvent.MOUSE_DOWN)
 *   {
 *     this.container.focus();
 *   }
 *   
 *   graphFireMouseEvent.apply(this, arguments);
 * };
 * (end)
 *
 * Constructor: mxCellEditor
 *
 * Constructs a new in-place editor for the specified graph.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxCellEditor(graph)
{
\tthis.graph = graph;
\t
\t// Stops editing after zoom changes
\tthis.zoomHandler = mxUtils.bind(this, function()
\t{
\t\tif (this.graph.isEditing())
\t\t{
\t\t\tthis.resize();
\t\t}
\t});
\t
\tthis.graph.view.addListener(mxEvent.SCALE, this.zoomHandler);
\tthis.graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.zoomHandler);
\t
\t// Adds handling of deleted cells while editing
\tthis.changeHandler = mxUtils.bind(this, function(sender)
\t{
\t\tif (this.editingCell != null && this.graph.getView().getState(this.editingCell) == null)
\t\t{
\t\t\tthis.stopEditing(true);
\t\t}
\t});

\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxCellEditor.prototype.graph = null;

/**
 * Variable: textarea
 *
 * Holds the DIV that is used for text editing. Note that this may be null before the first
 * edit. Instantiated in <init>.
 */
mxCellEditor.prototype.textarea = null;

/**
 * Variable: editingCell
 * 
 * Reference to the <mxCell> that is currently being edited.
 */
mxCellEditor.prototype.editingCell = null;

/**
 * Variable: trigger
 * 
 * Reference to the event that was used to start editing.
 */
mxCellEditor.prototype.trigger = null;

/**
 * Variable: modified
 * 
 * Specifies if the label has been modified.
 */
mxCellEditor.prototype.modified = false;

/**
 * Variable: autoSize
 * 
 * Specifies if the textarea should be resized while the text is being edited.
 * Default is true.
 */
mxCellEditor.prototype.autoSize = true;

/**
 * Variable: selectText
 * 
 * Specifies if the text should be selected when editing starts. Default is
 * true.
 */
mxCellEditor.prototype.selectText = true;

/**
 * Variable: emptyLabelText
 * 
 * Text to be displayed for empty labels. Default is '' or '<br>' in Firefox as
 * a workaround for the missing cursor bug for empty content editable. This can
 * be set to eg. \"[Type Here]\" to easier visualize editing of empty labels. The
 * value is only displayed before the first keystroke and is never used as the
 * actual editing value.
 */
mxCellEditor.prototype.emptyLabelText = (mxClient.IS_FF) ? '<br>' : '';

/**
 * Variable: escapeCancelsEditing
 * 
 * If true, pressing the escape key will stop editing and not accept the new
 * value. Change this to false to accept the new value on escape, and cancel
 * editing on Shift+Escape instead. Default is true.
 */
mxCellEditor.prototype.escapeCancelsEditing = true;

/**
 * Variable: textNode
 * 
 * Reference to the label DOM node that has been hidden.
 */
mxCellEditor.prototype.textNode = '';

/**
 * Variable: zIndex
 * 
 * Specifies the zIndex for the textarea. Default is 5.
 */
mxCellEditor.prototype.zIndex = 5;

/**
 * Variable: minResize
 * 
 * Defines the minimum width and height to be used in <resize>. Default is 0x20px.
 */
mxCellEditor.prototype.minResize = new mxRectangle(0, 20);

/**
 * Variable: wordWrapPadding
 * 
 * Correction factor for word wrapping width. Default is 2 in quirks, 0 in IE
 * 11 and 1 in all other browsers and modes.
 */
mxCellEditor.prototype.wordWrapPadding = (mxClient.IS_QUIRKS) ? 2 : (!mxClient.IS_IE11) ? 1 : 0;

/**
 * Variable: blurEnabled
 *
 * If <focusLost> should be called if <textarea> loses the focus. Default is false.
 */
mxCellEditor.prototype.blurEnabled = false;

/**
 * Variable: initialValue
 * 
 * Holds the initial editing value to check if the current value was modified.
 */
mxCellEditor.prototype.initialValue = null;

/**
 * Variable: align
 * 
 * Holds the current temporary horizontal alignment for the cell style. If this
 * is modified then the current text alignment is changed and the cell style is
 * updated when the value is applied.
 */
mxCellEditor.prototype.align = null;

/**
 * Function: init
 *
 * Creates the <textarea> and installs the event listeners. The key handler
 * updates the <modified> state.
 */
mxCellEditor.prototype.init = function ()
{
\tthis.textarea = document.createElement('div');
\tthis.textarea.className = 'mxCellEditor mxPlainTextEditor';
\tthis.textarea.contentEditable = true;
\t
\t// Workaround for selection outside of DIV if height is 0
\tif (mxClient.IS_GC)
\t{
\t\tthis.textarea.style.minHeight = '1em';
\t}

\tthis.textarea.style.position = ((this.isLegacyEditor())) ? 'absolute' : 'relative';
\tthis.installListeners(this.textarea);
};

/**
 * Function: applyValue
 * 
 * Called in <stopEditing> if cancel is false to invoke <mxGraph.labelChanged>.
 */
mxCellEditor.prototype.applyValue = function(state, value)
{
\tthis.graph.labelChanged(state.cell, value, this.trigger);
};

/**
 * Function: setAlign
 * 
 * Sets the temporary horizontal alignment for the current editing session.
 */
mxCellEditor.prototype.setAlign = function (align)
{
\tif (this.textarea != null)
\t{
\t\tthis.textarea.style.textAlign = align;
\t}
\t
\tthis.align = align;
\tthis.resize();
};

/**
 * Function: getInitialValue
 * 
 * Gets the initial editing value for the given cell.
 */
mxCellEditor.prototype.getInitialValue = function(state, trigger)
{
\tvar result = mxUtils.htmlEntities(this.graph.getEditingValue(state.cell, trigger), false);
\t
    // Workaround for trailing line breaks being ignored in the editor
\tif (!mxClient.IS_QUIRKS && document.documentMode != 8 && document.documentMode != 9 &&
\t\tdocument.documentMode != 10)
\t{
\t\tresult = mxUtils.replaceTrailingNewlines(result, '<div><br></div>');
\t}
    
    return result.replace(/\\n/g, '<br>');
};

/**
 * Function: getCurrentValue
 * 
 * Returns the current editing value.
 */
mxCellEditor.prototype.getCurrentValue = function(state)
{
\treturn mxUtils.extractTextWithWhitespace(this.textarea.childNodes);
};

/**
 * Function: isCancelEditingKeyEvent
 * 
 * Returns true if <escapeCancelsEditing> is true and shift, control and meta
 * are not pressed.
 */
mxCellEditor.prototype.isCancelEditingKeyEvent = function(evt)
{
\treturn this.escapeCancelsEditing || mxEvent.isShiftDown(evt) || mxEvent.isControlDown(evt) || mxEvent.isMetaDown(evt);
};

/**
 * Function: installListeners
 * 
 * Installs listeners for focus, change and standard key event handling.
 */
mxCellEditor.prototype.installListeners = function(elt)
{
\t// Applies value if text is dragged
\t// LATER: Gesture mouse events ignored for starting move
\tmxEvent.addListener(elt, 'dragstart', mxUtils.bind(this, function(evt)
\t{
\t\tthis.graph.stopEditing(false);
\t\tmxEvent.consume(evt);
\t}));

\t// Applies value if focus is lost
\tmxEvent.addListener(elt, 'blur', mxUtils.bind(this, function(evt)
\t{
\t\tif (this.blurEnabled)
\t\t{
\t\t\tthis.focusLost(evt);
\t\t}
\t}));

\t// Updates modified state and handles placeholder text
\tmxEvent.addListener(elt, 'keydown', mxUtils.bind(this, function(evt)
\t{
\t\tif (!mxEvent.isConsumed(evt))
\t\t{
\t\t\tif (this.isStopEditingEvent(evt))
\t\t\t{
\t\t\t\tthis.graph.stopEditing(false);
\t\t\t\tmxEvent.consume(evt);
\t\t\t}
\t\t\telse if (evt.keyCode == 27 /* Escape */)
\t\t\t{
\t\t\t\tthis.graph.stopEditing(this.isCancelEditingKeyEvent(evt));
\t\t\t\tmxEvent.consume(evt);
\t\t\t}
\t\t}
\t}));

\t// Keypress only fires if printable key was pressed and handles removing the empty placeholder
\tvar keypressHandler = mxUtils.bind(this, function(evt)
\t{
\t\tif (this.editingCell != null)
\t\t{
\t\t\t// Clears the initial empty label on the first keystroke
\t\t\t// and workaround for FF which fires keypress for delete and backspace
\t\t\tif (this.clearOnChange && elt.innerHTML == this.getEmptyLabelText() &&
\t\t\t\t(!mxClient.IS_FF || (evt.keyCode != 8 /* Backspace */ && evt.keyCode != 46 /* Delete */)))
\t\t\t{
\t\t\t\tthis.clearOnChange = false;
\t\t\t\telt.innerHTML = '';
\t\t\t}
\t\t}
\t});

\tmxEvent.addListener(elt, 'keypress', keypressHandler);
\tmxEvent.addListener(elt, 'paste', keypressHandler);
\t
\t// Handler for updating the empty label text value after a change
\tvar keyupHandler = mxUtils.bind(this, function(evt)
\t{
\t\tif (this.editingCell != null)
\t\t{
\t\t\t// Uses an optional text value for sempty labels which is cleared
\t\t\t// when the first keystroke appears. This makes it easier to see
\t\t\t// that a label is being edited even if the label is empty.
\t\t\t// In Safari and FF, an empty text is represented by <BR> which isn't enough to force a valid size
\t\t\tif (this.textarea.innerHTML.length == 0 || this.textarea.innerHTML == '<br>')
\t\t\t{
\t\t\t\tthis.textarea.innerHTML = this.getEmptyLabelText();
\t\t\t\tthis.clearOnChange = this.textarea.innerHTML.length > 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.clearOnChange = false;
\t\t\t}
\t\t}
\t});

\tmxEvent.addListener(elt, (!mxClient.IS_IE11 && !mxClient.IS_IE) ? 'input' : 'keyup', keyupHandler);
\tmxEvent.addListener(elt, 'cut', keyupHandler);
\tmxEvent.addListener(elt, 'paste', keyupHandler);

\t// Adds automatic resizing of the textbox while typing using input, keyup and/or DOM change events
\tvar evtName = (!mxClient.IS_IE11 && !mxClient.IS_IE) ? 'input' : 'keydown';
\t
\tvar resizeHandler = mxUtils.bind(this, function(evt)
\t{
\t\tif (this.editingCell != null && this.autoSize && !mxEvent.isConsumed(evt))
\t\t{
\t\t\t// Asynchronous is needed for keydown and shows better results for input events overall
\t\t\t// (ie non-blocking and cases where the offsetWidth/-Height was wrong at this time)
\t\t\tif (this.resizeThread != null)
\t\t\t{
\t\t\t\twindow.clearTimeout(this.resizeThread);
\t\t\t}
\t\t\t
\t\t\tthis.resizeThread = window.setTimeout(mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tthis.resizeThread = null;
\t\t\t\tthis.resize();
\t\t\t}), 0);
\t\t}
\t});
\t
\tmxEvent.addListener(elt, evtName, resizeHandler);
\tmxEvent.addListener(window, 'resize', resizeHandler);

\tif (document.documentMode >= 9)
\t{
\t\tmxEvent.addListener(elt, 'DOMNodeRemoved', resizeHandler);
\t\tmxEvent.addListener(elt, 'DOMNodeInserted', resizeHandler);
\t}
\telse
\t{
\t\tmxEvent.addListener(elt, 'cut', resizeHandler);
\t\tmxEvent.addListener(elt, 'paste', resizeHandler);
\t}
};

/**
 * Function: isStopEditingEvent
 * 
 * Returns true if the given keydown event should stop cell editing. This
 * returns true if F2 is pressed of if <mxGraph.enterStopsCellEditing> is true
 * and enter is pressed without control or shift.
 */
mxCellEditor.prototype.isStopEditingEvent = function(evt)
{
\treturn evt.keyCode == 113 /* F2 */ || (this.graph.isEnterStopsCellEditing() &&
\t\tevt.keyCode == 13 /* Enter */ && !mxEvent.isControlDown(evt) &&
\t\t!mxEvent.isShiftDown(evt));
};

/**
 * Function: isEventSource
 * 
 * Returns true if this editor is the source for the given native event.
 */
mxCellEditor.prototype.isEventSource = function(evt)
{
\treturn mxEvent.getSource(evt) == this.textarea;
};

/**
 * Function: resize
 * 
 * Returns <modified>.
 */
mxCellEditor.prototype.resize = function()
{
\tvar state = this.graph.getView().getState(this.editingCell);
\t
\tif (state == null)
\t{
\t\tthis.stopEditing(true);
\t}
\telse if (this.textarea != null)
\t{
\t\tvar isEdge = this.graph.getModel().isEdge(state.cell);
 \t\tvar scale = this.graph.getView().scale;
 \t\tvar m = null;
\t\t
\t\tif (!this.autoSize || (state.style[mxConstants.STYLE_OVERFLOW] == 'fill'))
\t\t{
\t\t\t// Specifies the bounds of the editor box
\t\t\tthis.bounds = this.getEditorBounds(state);
\t\t\tthis.textarea.style.width = Math.round(this.bounds.width / scale) + 'px';
\t\t\tthis.textarea.style.height = Math.round(this.bounds.height / scale) + 'px';
\t\t\t
\t\t\t// FIXME: Offset when scaled
\t\t\tif (document.documentMode == 8 || mxClient.IS_QUIRKS)
\t\t\t{
\t\t\t\tthis.textarea.style.left = Math.round(this.bounds.x) + 'px';
\t\t\t\tthis.textarea.style.top = Math.round(this.bounds.y) + 'px';
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.textarea.style.left = Math.max(0, Math.round(this.bounds.x + 1)) + 'px';
\t\t\t\tthis.textarea.style.top = Math.max(0, Math.round(this.bounds.y + 1)) + 'px';
\t\t\t}
\t\t\t
\t\t\t// Installs native word wrapping and avoids word wrap for empty label placeholder
\t\t\tif (this.graph.isWrapping(state.cell) && (this.bounds.width >= 2 || this.bounds.height >= 2) &&
\t\t\t\tthis.textarea.innerHTML != this.getEmptyLabelText())
\t\t\t{
\t\t\t\tthis.textarea.style.wordWrap = mxConstants.WORD_WRAP;
\t\t\t\tthis.textarea.style.whiteSpace = 'normal';
\t\t\t\t
\t\t\t\tif (state.style[mxConstants.STYLE_OVERFLOW] != 'fill')
\t\t\t\t{
\t\t\t\t\tthis.textarea.style.width = Math.round(this.bounds.width / scale) + this.wordWrapPadding + 'px';
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.textarea.style.whiteSpace = 'nowrap';
\t\t\t\t
\t\t\t\tif (state.style[mxConstants.STYLE_OVERFLOW] != 'fill')
\t\t\t\t{
\t\t\t\t\tthis.textarea.style.width = '';
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t \t{
\t \t\tvar lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
\t\t\tm = (state.text != null && this.align == null) ? state.text.margin : null;
\t\t\t
\t\t\tif (m == null)
\t\t\t{
\t\t\t\tm = mxUtils.getAlignmentAsPoint(this.align || mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER),
\t\t\t\t\t\tmxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE));
\t\t\t}
\t\t\t
\t \t\tif (isEdge)
\t\t\t{
\t\t\t\tthis.bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y, 0, 0);
\t\t\t\t
\t\t\t\tif (lw != null)
\t\t\t \t{
\t\t\t\t\tvar tmp = (parseFloat(lw) + 2) * scale;
\t\t\t\t\tthis.bounds.width = tmp;
\t\t\t\t\tthis.bounds.x += m.x * tmp;
\t\t\t \t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar bds = mxRectangle.fromRectangle(state);
\t\t\t\tvar hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t\t\t\tvar vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);

\t\t\t\tbds = (state.shape != null && hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE) ? state.shape.getLabelBounds(bds) : bds;
\t\t\t \t
\t\t\t \tif (lw != null)
\t\t\t \t{
\t\t\t \t\tbds.width = parseFloat(lw) * scale;
\t\t\t \t}
\t\t\t \t
\t\t\t \tif (!state.view.graph.cellRenderer.legacySpacing || state.style[mxConstants.STYLE_OVERFLOW] != 'width')
\t\t\t \t{
\t\t\t\t\tvar spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 2) * scale;
\t\t\t\t\tvar spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0) + mxText.prototype.baseSpacingTop) * scale + spacing;
\t\t\t\t\tvar spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0) + mxText.prototype.baseSpacingRight) * scale + spacing;
\t\t\t\t\tvar spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0) + mxText.prototype.baseSpacingBottom) * scale + spacing;
\t\t\t\t\tvar spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0) + mxText.prototype.baseSpacingLeft) * scale + spacing;
\t\t\t\t\t
\t\t\t\t\tvar hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t\t\t\t\tvar vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);

\t\t\t\t\tbds = new mxRectangle(bds.x + spacingLeft, bds.y + spacingTop,
\t\t\t\t\t\tbds.width - ((hpos == mxConstants.ALIGN_CENTER && lw == null) ? (spacingLeft + spacingRight) : 0),
\t\t\t\t\t\tbds.height - ((vpos == mxConstants.ALIGN_MIDDLE) ? (spacingTop + spacingBottom) : 0));
\t\t\t \t}

\t\t\t\tthis.bounds = new mxRectangle(bds.x + state.absoluteOffset.x, bds.y + state.absoluteOffset.y, bds.width, bds.height);
\t\t\t}

\t\t\t// Needed for word wrap inside text blocks with oversize lines to match the final result where
\t \t\t// the width of the longest line is used as the reference for text alignment in the cell
\t \t\t// TODO: Fix word wrapping preview for edge labels in helloworld.html
\t\t\tif (this.graph.isWrapping(state.cell) && (this.bounds.width >= 2 || this.bounds.height >= 2) &&
\t\t\t\tthis.textarea.innerHTML != this.getEmptyLabelText())
\t\t\t{
\t\t\t\tthis.textarea.style.wordWrap = mxConstants.WORD_WRAP;
\t\t\t\tthis.textarea.style.whiteSpace = 'normal';
\t\t\t\t
\t\t \t\t// Forces automatic reflow if text is removed from an oversize label and normal word wrap
\t\t\t\tvar tmp = Math.round(this.bounds.width / ((document.documentMode == 8) ? scale : scale)) + this.wordWrapPadding;

\t\t\t\tif (this.textarea.style.position != 'relative')
\t\t\t\t{
\t\t\t\t\tthis.textarea.style.width = tmp + 'px';
\t\t\t\t\t
\t\t\t\t\tif (this.textarea.scrollWidth > tmp)
\t\t\t\t\t{
\t\t\t\t\t\tthis.textarea.style.width = this.textarea.scrollWidth + 'px';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.textarea.style.maxWidth = tmp + 'px';
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// KNOWN: Trailing cursor in IE9 quirks mode is not visible
\t\t\t\tthis.textarea.style.whiteSpace = 'nowrap';
\t\t\t\tthis.textarea.style.width = '';
\t\t\t}
\t\t\t
\t\t\t// LATER: Keep in visible area, add fine tuning for pixel precision
\t\t\t// Workaround for wrong measuring in IE8 standards
\t\t\tif (document.documentMode == 8)
\t\t\t{
\t\t\t\tthis.textarea.style.zoom = '1';
\t\t\t\tthis.textarea.style.height = 'auto';
\t\t\t}
\t\t\t
\t\t\tvar ow = this.textarea.scrollWidth;
\t\t\tvar oh = this.textarea.scrollHeight;
\t\t\t
\t\t\t// TODO: Update CSS width and height if smaller than minResize or remove minResize
\t\t\t//if (this.minResize != null)
\t\t\t//{
\t\t\t//\tow = Math.max(ow, this.minResize.width);
\t\t\t//\toh = Math.max(oh, this.minResize.height);
\t\t\t//}
\t\t\t
\t\t\t// LATER: Keep in visible area, add fine tuning for pixel precision
\t\t\tif (document.documentMode == 8)
\t\t\t{
\t\t\t\t// LATER: Scaled wrapping and position is wrong in IE8
\t\t\t\tthis.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';
\t\t\t\tthis.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';
\t\t\t\t// Workaround for wrong event handling width and height
\t\t\t\tthis.textarea.style.width = Math.round(ow * scale) + 'px';
\t\t\t\tthis.textarea.style.height = Math.round(oh * scale) + 'px';
\t\t\t}
\t\t\telse if (mxClient.IS_QUIRKS)
\t\t\t{\t\t\t
\t\t\t\tthis.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';
\t\t\t\tthis.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';
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.textarea.style.left = Math.max(0, Math.round(this.bounds.x - m.x * (this.bounds.width - 2)) + 1) + 'px';
\t\t\t\tthis.textarea.style.top = Math.max(0, Math.round(this.bounds.y - m.y * (this.bounds.height - 4) + ((m.y == -1) ? 3 : 0)) + 1) + 'px';
\t\t\t}
\t \t}

\t\tif (mxClient.IS_VML)
\t\t{
\t\t\tthis.textarea.style.zoom = scale;
\t\t}
\t\telse
\t\t{
\t\t\tmxUtils.setPrefixedStyle(this.textarea.style, 'transformOrigin', '0px 0px');
\t\t\tmxUtils.setPrefixedStyle(this.textarea.style, 'transform',
\t\t\t\t'scale(' + scale + ',' + scale + ')' + ((m == null) ? '' :
\t\t\t\t' translate(' + (m.x * 100) + '%,' + (m.y * 100) + '%)'));
\t\t}
\t}
};

/**
 * Function: focusLost
 *
 * Called if the textarea has lost focus.
 */
mxCellEditor.prototype.focusLost = function()
{
\tthis.stopEditing(!this.graph.isInvokesStopCellEditing());
};

/**
 * Function: getBackgroundColor
 * 
 * Returns the background color for the in-place editor. This implementation
 * always returns null.
 */
mxCellEditor.prototype.getBackgroundColor = function(state)
{
\treturn null;
};

/**
 * Function: isLegacyEditor
 * 
 * Returns true if max-width is not supported or if the SVG root element in
 * in the graph does not have CSS position absolute. In these cases the text
 * editor must use CSS position absolute to avoid an offset but it will have
 * a less accurate line wrapping width during the text editing preview. This
 * implementation returns true for IE8- and quirks mode or if the CSS position
 * of the SVG element is not absolute.
 */
mxCellEditor.prototype.isLegacyEditor = function()
{
\tif (mxClient.IS_VML)
\t{
\t\treturn true;
\t}
\telse
\t{
\t\tvar absoluteRoot = false;
\t\t
\t\tif (mxClient.IS_SVG)
\t\t{
\t\t\tvar root = this.graph.view.getDrawPane().ownerSVGElement;
\t\t\t
\t\t\tif (root != null)
\t\t\t{
\t\t\t\tvar css = mxUtils.getCurrentStyle(root);
\t\t\t\t
\t\t\t\tif (css != null)
\t\t\t\t{\t\t\t\t
\t\t\t\t\tabsoluteRoot = css.position == 'absolute';
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn !absoluteRoot;
\t}
};

/**
 * Function: startEditing
 *
 * Starts the editor for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to start editing.
 * trigger - Optional mouse event that triggered the editor.
 */
mxCellEditor.prototype.startEditing = function(cell, trigger)
{
\tthis.stopEditing(true);
\tthis.align = null;
\t
\t// Creates new textarea instance
\tif (this.textarea == null)
\t{
\t\tthis.init();
\t}
\t
\tif (this.graph.tooltipHandler != null)
\t{
\t\tthis.graph.tooltipHandler.hideTooltip();
\t}
\t
\tvar state = this.graph.getView().getState(cell);
\t
\tif (state != null)
\t{
\t\t// Configures the style of the in-place editor
\t\tvar scale = this.graph.getView().scale;
\t\tvar size = mxUtils.getValue(state.style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE);
\t\tvar family = mxUtils.getValue(state.style, mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY);
\t\tvar color = mxUtils.getValue(state.style, mxConstants.STYLE_FONTCOLOR, 'black');
\t\tvar align = mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_LEFT);
\t\tvar bold = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
\t\t\t\tmxConstants.FONT_BOLD) == mxConstants.FONT_BOLD;
\t\tvar italic = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
\t\t\t\tmxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC;
\t\tvar txtDecor = [];
\t\t
\t\tif ((mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
\t\t\t\tmxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
\t\t{
\t\t\ttxtDecor.push('underline');
\t\t}
\t\t
\t\tif ((mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
\t\t\t\tmxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
\t\t{
\t\t\ttxtDecor.push('line-through');
\t\t}
\t\t
\t\tthis.textarea.style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? Math.round(size * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
\t\tthis.textarea.style.backgroundColor = this.getBackgroundColor(state);
\t\tthis.textarea.style.textDecoration = txtDecor.join(' ');
\t\tthis.textarea.style.fontWeight = (bold) ? 'bold' : 'normal';
\t\tthis.textarea.style.fontStyle = (italic) ? 'italic' : '';
\t\tthis.textarea.style.fontSize = Math.round(size) + 'px';
\t\tthis.textarea.style.zIndex = this.zIndex;
\t\tthis.textarea.style.fontFamily = family;
\t\tthis.textarea.style.textAlign = align;
\t\tthis.textarea.style.outline = 'none';
\t\tthis.textarea.style.color = color;
\t\t
\t\tvar dir = this.textDirection = mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
\t\t
\t\tif (dir == mxConstants.TEXT_DIRECTION_AUTO)
\t\t{
\t\t\tif (state != null && state.text != null && state.text.dialect != mxConstants.DIALECT_STRICTHTML &&
\t\t\t\t!mxUtils.isNode(state.text.value))
\t\t\t{
\t\t\t\tdir = state.text.getAutoDirection();
\t\t\t}
\t\t}
\t\t
\t\tif (dir == mxConstants.TEXT_DIRECTION_LTR || dir == mxConstants.TEXT_DIRECTION_RTL)
\t\t{
\t\t\tthis.textarea.setAttribute('dir', dir);
\t\t}
\t\telse
\t\t{
\t\t\tthis.textarea.removeAttribute('dir');
\t\t}

\t\t// Sets the initial editing value
\t\tthis.textarea.innerHTML = this.getInitialValue(state, trigger) || '';
\t\tthis.initialValue = this.textarea.innerHTML;

\t\t// Uses an optional text value for empty labels which is cleared
\t\t// when the first keystroke appears. This makes it easier to see
\t\t// that a label is being edited even if the label is empty.
\t\tif (this.textarea.innerHTML.length == 0 || this.textarea.innerHTML == '<br>')
\t\t{
\t\t\tthis.textarea.innerHTML = this.getEmptyLabelText();
\t\t\tthis.clearOnChange = true;
\t\t}
\t\telse
\t\t{
\t\t\tthis.clearOnChange = this.textarea.innerHTML == this.getEmptyLabelText();
\t\t}

\t\tthis.graph.container.appendChild(this.textarea);
\t\t
\t\t// Update this after firing all potential events that could update the cleanOnChange flag
\t\tthis.editingCell = cell;
\t\tthis.trigger = trigger;
\t\tthis.textNode = null;

\t\tif (state.text != null && this.isHideLabel(state))
\t\t{
\t\t\tthis.textNode = state.text.node;
\t\t\tthis.textNode.style.visibility = 'hidden';
\t\t}

\t\t// Workaround for initial offsetHeight not ready for heading in markup
\t\tif (this.autoSize && (this.graph.model.isEdge(state.cell) || state.style[mxConstants.STYLE_OVERFLOW] != 'fill'))
\t\t{
\t\t\twindow.setTimeout(mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tthis.resize();
\t\t\t}), 0);
\t\t}
\t\t
\t\tthis.resize();
\t\t
\t\t// Workaround for NS_ERROR_FAILURE in FF
\t\ttry
\t\t{
\t\t\t// Prefers blinking cursor over no selected text if empty
\t\t\tthis.textarea.focus();
\t\t\t
\t\t\tif (this.isSelectText() && this.textarea.innerHTML.length > 0 &&
\t\t\t\t(this.textarea.innerHTML != this.getEmptyLabelText() || !this.clearOnChange))
\t\t\t{
\t\t\t\tdocument.execCommand('selectAll', false, null);
\t\t\t}
\t\t}
\t\tcatch (e)
\t\t{
\t\t\t// ignore
\t\t}
\t}
};

/**
 * Function: isSelectText
 * 
 * Returns <selectText>.
 */
mxCellEditor.prototype.isSelectText = function()
{
\treturn this.selectText;
};

/**
 * Function: clearSelection
 * 
 * Clears the selection.
 */
mxCellEditor.prototype.clearSelection = function()
{
\tvar selection = null;
\t
\tif (window.getSelection)
\t{
\t\tselection = window.getSelection();
\t}
\telse if (document.selection)
\t{
\t\tselection = document.selection;
\t}
\t
\tif (selection != null)
\t{
\t\tif (selection.empty)
\t\t{
\t\t\tselection.empty();
\t\t}
\t\telse if (selection.removeAllRanges)
\t\t{
\t\t\tselection.removeAllRanges();
\t\t}
\t}
};

/**
 * Function: stopEditing
 *
 * Stops the editor and applies the value if cancel is false.
 */
mxCellEditor.prototype.stopEditing = function(cancel)
{
\tcancel = cancel || false;
\t
\tif (this.editingCell != null)
\t{
\t\tif (this.textNode != null)
\t\t{
\t\t\tthis.textNode.style.visibility = 'visible';
\t\t\tthis.textNode = null;
\t\t}

\t\tvar state = (!cancel) ? this.graph.view.getState(this.editingCell) : null;

\t\tvar initial = this.initialValue;
\t\tthis.initialValue = null;
\t\tthis.editingCell = null;
\t\tthis.trigger = null;
\t\tthis.bounds = null;
\t\tthis.textarea.blur();
\t\tthis.clearSelection();
\t\t
\t\tif (this.textarea.parentNode != null)
\t\t{
\t\t\tthis.textarea.parentNode.removeChild(this.textarea);
\t\t}
\t\t
\t\tif (this.clearOnChange && this.textarea.innerHTML == this.getEmptyLabelText())
\t\t{
\t\t\tthis.textarea.innerHTML = '';
\t\t\tthis.clearOnChange = false;
\t\t}

\t\tif (state != null && (this.textarea.innerHTML != initial || this.align != null))
\t\t{
\t\t\tthis.prepareTextarea();
\t\t\tvar value = this.getCurrentValue(state);
\t\t\t
\t\t\tthis.graph.getModel().beginUpdate();
\t\t\ttry
\t\t\t{
\t\t\t\tif (value != null)
\t\t\t\t{
\t\t\t\t\tthis.applyValue(state, value);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (this.align != null)
\t\t\t\t{
\t\t\t\t\tthis.graph.setCellStyles(mxConstants.STYLE_ALIGN, this.align, [state.cell]);
\t\t\t\t}
\t\t\t}
\t\t\tfinally
\t\t\t{
\t\t\t\tthis.graph.getModel().endUpdate();
\t\t\t}
\t\t}
\t\t
\t\t// Forces new instance on next edit for undo history reset
\t\tmxEvent.release(this.textarea);
\t\tthis.textarea = null;
\t\tthis.align = null;
\t}
};

/**
 * Function: prepareTextarea
 * 
 * Prepares the textarea for getting its value in <stopEditing>.
 * This implementation removes the extra trailing linefeed in Firefox.
 */
mxCellEditor.prototype.prepareTextarea = function()
{
\tif (this.textarea.lastChild != null &&
\t\tthis.textarea.lastChild.nodeName == 'BR')
\t{
\t\tthis.textarea.removeChild(this.textarea.lastChild);
\t}
};

/**
 * Function: isHideLabel
 * 
 * Returns true if the label should be hidden while the cell is being
 * edited.
 */
mxCellEditor.prototype.isHideLabel = function(state)
{
\treturn true;
};

/**
 * Function: getMinimumSize
 * 
 * Returns the minimum width and height for editing the given state.
 */
mxCellEditor.prototype.getMinimumSize = function(state)
{
\tvar scale = this.graph.getView().scale;
\t
\treturn new mxRectangle(0, 0, (state.text == null) ? 30 : state.text.size * scale + 20,
\t\t\t(this.textarea.style.textAlign == 'left') ? 120 : 40);
};

/**
 * Function: getEditorBounds
 * 
 * Returns the <mxRectangle> that defines the bounds of the editor.
 */
mxCellEditor.prototype.getEditorBounds = function(state)
{
\tvar isEdge = this.graph.getModel().isEdge(state.cell);
\tvar scale = this.graph.getView().scale;
\tvar minSize = this.getMinimumSize(state);
\tvar minWidth = minSize.width;
 \tvar minHeight = minSize.height;
 \tvar result = null;
 \t
 \tif (!isEdge && state.view.graph.cellRenderer.legacySpacing && state.style[mxConstants.STYLE_OVERFLOW] == 'fill')
 \t{
 \t\tresult = state.shape.getLabelBounds(mxRectangle.fromRectangle(state));
 \t}
 \telse
 \t{
\t\tvar spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 0) * scale;
\t\tvar spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0) + mxText.prototype.baseSpacingTop) * scale + spacing;
\t\tvar spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0) + mxText.prototype.baseSpacingRight) * scale + spacing;
\t\tvar spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0) + mxText.prototype.baseSpacingBottom) * scale + spacing;
\t\tvar spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0) + mxText.prototype.baseSpacingLeft) * scale + spacing;
\t
\t \tresult = new mxRectangle(state.x, state.y,
\t \t\t Math.max(minWidth, state.width - spacingLeft - spacingRight),
\t \t\t Math.max(minHeight, state.height - spacingTop - spacingBottom));
\t\tvar hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t\tvar vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
\t\t
\t\tresult = (state.shape != null && hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE) ? state.shape.getLabelBounds(result) : result;
\t
\t\tif (isEdge)
\t\t{
\t\t\tresult.x = state.absoluteOffset.x;
\t\t\tresult.y = state.absoluteOffset.y;
\t
\t\t\tif (state.text != null && state.text.boundingBox != null)
\t\t\t{
\t\t\t\t// Workaround for label containing just spaces in which case
\t\t\t\t// the bounding box location contains negative numbers 
\t\t\t\tif (state.text.boundingBox.x > 0)
\t\t\t\t{
\t\t\t\t\tresult.x = state.text.boundingBox.x;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (state.text.boundingBox.y > 0)
\t\t\t\t{
\t\t\t\t\tresult.y = state.text.boundingBox.y;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (state.text != null && state.text.boundingBox != null)
\t\t{
\t\t\tresult.x = Math.min(result.x, state.text.boundingBox.x);
\t\t\tresult.y = Math.min(result.y, state.text.boundingBox.y);
\t\t}
\t
\t\tresult.x += spacingLeft;
\t\tresult.y += spacingTop;
\t
\t\tif (state.text != null && state.text.boundingBox != null)
\t\t{
\t\t\tif (!isEdge)
\t\t\t{
\t\t\t\tresult.width = Math.max(result.width, state.text.boundingBox.width);
\t\t\t\tresult.height = Math.max(result.height, state.text.boundingBox.height);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.width = Math.max(minWidth, state.text.boundingBox.width);
\t\t\t\tresult.height = Math.max(minHeight, state.text.boundingBox.height);
\t\t\t}
\t\t}
\t\t
\t\t// Applies the horizontal and vertical label positions
\t\tif (this.graph.getModel().isVertex(state.cell))
\t\t{
\t\t\tvar horizontal = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t
\t\t\tif (horizontal == mxConstants.ALIGN_LEFT)
\t\t\t{
\t\t\t\tresult.x -= state.width;
\t\t\t}
\t\t\telse if (horizontal == mxConstants.ALIGN_RIGHT)
\t\t\t{
\t\t\t\tresult.x += state.width;
\t\t\t}
\t
\t\t\tvar vertical = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
\t
\t\t\tif (vertical == mxConstants.ALIGN_TOP)
\t\t\t{
\t\t\t\tresult.y -= state.height;
\t\t\t}
\t\t\telse if (vertical == mxConstants.ALIGN_BOTTOM)
\t\t\t{
\t\t\t\tresult.y += state.height;
\t\t\t}
\t\t}
 \t}
 \t
 \treturn new mxRectangle(Math.round(result.x), Math.round(result.y), Math.round(result.width), Math.round(result.height));
};

/**
 * Function: getEmptyLabelText
 *
 * Returns the initial label value to be used of the label of the given
 * cell is empty. This label is displayed and cleared on the first keystroke.
 * This implementation returns <emptyLabelText>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which a text for an empty editing box should be
 * returned.
 */
mxCellEditor.prototype.getEmptyLabelText = function (cell)
{
\treturn this.emptyLabelText;
};

/**
 * Function: getEditingCell
 *
 * Returns the cell that is currently being edited or null if no cell is
 * being edited.
 */
mxCellEditor.prototype.getEditingCell = function ()
{
\treturn this.editingCell;
};

/**
 * Function: destroy
 *
 * Destroys the editor and removes all associated resources.
 */
mxCellEditor.prototype.destroy = function ()
{
\tif (this.textarea != null)
\t{
\t\tmxEvent.release(this.textarea);
\t\t
\t\tif (this.textarea.parentNode != null)
\t\t{
\t\t\tthis.textarea.parentNode.removeChild(this.textarea);
\t\t}
\t\t
\t\tthis.textarea = null;

\t}
\t\t\t
\tif (this.changeHandler != null)
\t{
\t\tthis.graph.getModel().removeListener(this.changeHandler);
\t\tthis.changeHandler = null;
\t}

\tif (this.zoomHandler)
\t{
\t\tthis.graph.view.removeListener(this.zoomHandler);
\t\tthis.zoomHandler = null;
\t}
};
/**
 * Copyright (c) 2006-2017, JGraph Ltd
 * Copyright (c) 2006-2017, Gaudenz Alder
 */
/**
 * Class: mxCellRenderer
 * 
 * Renders cells into a document object model. The <defaultShapes> is a global
 * map of shapename, constructor pairs that is used in all instances. You can
 * get a list of all available shape names using the following code.
 * 
 * In general the cell renderer is in charge of creating, redrawing and
 * destroying the shape and label associated with a cell state, as well as
 * some other graphical objects, namely controls and overlays. The shape
 * hieararchy in the display (ie. the hierarchy in which the DOM nodes
 * appear in the document) does not reflect the cell hierarchy. The shapes
 * are a (flat) sequence of shapes and labels inside the draw pane of the
 * graph view, with some exceptions, namely the HTML labels being placed
 * directly inside the graph container for certain browsers.
 * 
 * (code)
 * mxLog.show();
 * for (var i in mxCellRenderer.defaultShapes)
 * {
 *   mxLog.debug(i);
 * }
 * (end)
 *
 * Constructor: mxCellRenderer
 * 
 * Constructs a new cell renderer with the following built-in shapes:
 * arrow, rectangle, ellipse, rhombus, image, line, label, cylinder,
 * swimlane, connector, actor and cloud.
 */
function mxCellRenderer() { };

/**
 * Variable: defaultShapes
 * 
 * Static array that contains the globally registered shapes which are
 * known to all instances of this class. For adding new shapes you should
 * use the static <mxCellRenderer.registerShape> function.
 */
mxCellRenderer.defaultShapes = new Object();

/**
 * Variable: defaultEdgeShape
 * 
 * Defines the default shape for edges. Default is <mxConnector>.
 */
mxCellRenderer.prototype.defaultEdgeShape = mxConnector;

/**
 * Variable: defaultVertexShape
 * 
 * Defines the default shape for vertices. Default is <mxRectangleShape>.
 */
mxCellRenderer.prototype.defaultVertexShape = mxRectangleShape;

/**
 * Variable: defaultTextShape
 * 
 * Defines the default shape for labels. Default is <mxText>.
 */
mxCellRenderer.prototype.defaultTextShape = mxText;

/**
 * Variable: legacyControlPosition
 * 
 * Specifies if the folding icon should ignore the horizontal
 * orientation of a swimlane. Default is true.
 */
mxCellRenderer.prototype.legacyControlPosition = true;

/**
 * Variable: legacySpacing
 * 
 * Specifies if spacing and label position should be ignored if overflow is
 * fill or width. Default is true for backwards compatiblity.
 */
mxCellRenderer.prototype.legacySpacing = true;

/**
 * Variable: antiAlias
 * 
 * Anti-aliasing option for new shapes. Default is true.
 */
mxCellRenderer.prototype.antiAlias = true;

/**
 * Variable: minSvgStrokeWidth
 * 
 * Minimum stroke width for SVG output.
 */
mxCellRenderer.prototype.minSvgStrokeWidth = 1;

/**
 * Variable: forceControlClickHandler
 * 
 * Specifies if the enabled state of the graph should be ignored in the control
 * click handler (to allow folding in disabled graphs). Default is false.
 */
mxCellRenderer.prototype.forceControlClickHandler = false;

/**
 * Function: registerShape
 * 
 * Registers the given constructor under the specified key in this instance
 * of the renderer.
 * 
 * Example:
 * 
 * (code)
 * mxCellRenderer.registerShape(mxConstants.SHAPE_RECTANGLE, mxRectangleShape);
 * (end)
 * 
 * Parameters:
 * 
 * key - String representing the shape name.
 * shape - Constructor of the <mxShape> subclass.
 */
mxCellRenderer.registerShape = function(key, shape)
{
\tmxCellRenderer.defaultShapes[key] = shape;
};

// Adds default shapes into the default shapes array
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);

/**
 * Function: initializeShape
 * 
 * Initializes the shape in the given state by calling its init method with
 * the correct container after configuring it using <configureShape>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the shape should be initialized.
 */
mxCellRenderer.prototype.initializeShape = function(state)
{
\tstate.shape.dialect = state.view.graph.dialect;
\tthis.configureShape(state);
\tstate.shape.init(state.view.getDrawPane());
};

/**
 * Function: createShape
 * 
 * Creates and returns the shape for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the shape should be created.
 */
mxCellRenderer.prototype.createShape = function(state)
{
\tvar shape = null;
\t
\tif (state.style != null)
\t{
\t\t// Checks if there is a stencil for the name and creates
\t\t// a shape instance for the stencil if one exists
\t\tvar stencil = mxStencilRegistry.getStencil(state.style[mxConstants.STYLE_SHAPE]);
\t\t
\t\tif (stencil != null)
\t\t{
\t\t\tshape = new mxShape(stencil);
\t\t}
\t\telse
\t\t{
\t\t\tvar ctor = this.getShapeConstructor(state);
\t\t\tshape = new ctor();
\t\t}
\t}
\t
\treturn shape;
};

/**
 * Function: createIndicatorShape
 * 
 * Creates the indicator shape for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the indicator shape should be created.
 */
mxCellRenderer.prototype.createIndicatorShape = function(state)
{
\tstate.shape.indicatorShape = this.getShape(state.view.graph.getIndicatorShape(state));
};

/**
 * Function: getShape
 * 
 * Returns the shape for the given name from <defaultShapes>.
 */
mxCellRenderer.prototype.getShape = function(name)
{
\treturn (name != null) ? mxCellRenderer.defaultShapes[name] : null;
};

/**
 * Function: getShapeConstructor
 * 
 * Returns the constructor to be used for creating the shape.
 */
mxCellRenderer.prototype.getShapeConstructor = function(state)
{
\tvar ctor = this.getShape(state.style[mxConstants.STYLE_SHAPE]);
\t
\tif (ctor == null)
\t{
\t\tctor = (state.view.graph.getModel().isEdge(state.cell)) ?
\t\t\tthis.defaultEdgeShape : this.defaultVertexShape;
\t}
\t
\treturn ctor;
};

/**
 * Function: configureShape
 * 
 * Configures the shape for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the shape should be configured.
 */
mxCellRenderer.prototype.configureShape = function(state)
{
\tstate.shape.apply(state);
\tstate.shape.image = state.view.graph.getImage(state);
\tstate.shape.indicatorColor = state.view.graph.getIndicatorColor(state);
\tstate.shape.indicatorStrokeColor = state.style[mxConstants.STYLE_INDICATOR_STROKECOLOR];
\tstate.shape.indicatorGradientColor = state.view.graph.getIndicatorGradientColor(state);
\tstate.shape.indicatorDirection = state.style[mxConstants.STYLE_INDICATOR_DIRECTION];
\tstate.shape.indicatorImage = state.view.graph.getIndicatorImage(state);

\tthis.postConfigureShape(state);
};

/**
 * Function: postConfigureShape
 * 
 * Replaces any reserved words used for attributes, eg. inherit,
 * indicated or swimlane for colors in the shape for the given state.
 * This implementation resolves these keywords on the fill, stroke
 * and gradient color keys.
 */
mxCellRenderer.prototype.postConfigureShape = function(state)
{
\tif (state.shape != null)
\t{
\t\tthis.resolveColor(state, 'indicatorGradientColor', mxConstants.STYLE_GRADIENTCOLOR);
\t\tthis.resolveColor(state, 'indicatorColor', mxConstants.STYLE_FILLCOLOR);
\t\tthis.resolveColor(state, 'gradient', mxConstants.STYLE_GRADIENTCOLOR);
\t\tthis.resolveColor(state, 'stroke', mxConstants.STYLE_STROKECOLOR);
\t\tthis.resolveColor(state, 'fill', mxConstants.STYLE_FILLCOLOR);
\t}
};

/**
 * Function: checkPlaceholderStyles
 * 
 * Checks if the style of the given <mxCellState> contains 'inherit',
 * 'indicated' or 'swimlane' for colors that support those keywords.
 */
mxCellRenderer.prototype.checkPlaceholderStyles = function(state)
{
\t// LATER: Check if the color has actually changed
\tif (state.style != null)
\t{
\t\tvar values = ['inherit', 'swimlane', 'indicated'];
\t\tvar styles = [mxConstants.STYLE_FILLCOLOR, mxConstants.STYLE_STROKECOLOR,
\t\t\tmxConstants.STYLE_GRADIENTCOLOR, mxConstants.STYLE_FONTCOLOR];
\t\t
\t\tfor (var i = 0; i < styles.length; i++)
\t\t{
\t\t\tif (mxUtils.indexOf(values, state.style[styles[i]]) >= 0)
\t\t\t{
\t\t\t\treturn true;
\t\t\t}
\t\t}
\t}
\t
\treturn false;
};

/**
 * Function: resolveColor
 * 
 * Resolves special keywords 'inherit', 'indicated' and 'swimlane' and sets
 * the respective color on the shape.
 */
mxCellRenderer.prototype.resolveColor = function(state, field, key)
{
\tvar shape = (key == mxConstants.STYLE_FONTCOLOR) ?
\t\tstate.text : state.shape;
\t
\tif (shape != null)
\t{
\t\tvar graph = state.view.graph;
\t\tvar value = shape[field];
\t\tvar referenced = null;
\t\t
\t\tif (value == 'inherit')
\t\t{
\t\t\treferenced = graph.model.getParent(state.cell);
\t\t}
\t\telse if (value == 'swimlane')
\t\t{
\t\t\tshape[field] = (key == mxConstants.STYLE_STROKECOLOR ||
\t\t\t\tkey == mxConstants.STYLE_FONTCOLOR) ?
\t\t\t\t'#000000' : '#ffffff';
\t\t\t
\t\t\tif (graph.model.getTerminal(state.cell, false) != null)
\t\t\t{
\t\t\t\treferenced = graph.model.getTerminal(state.cell, false);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treferenced = state.cell;
\t\t\t}
\t\t\t
\t\t\treferenced = graph.getSwimlane(referenced);
\t\t\tkey = graph.swimlaneIndicatorColorAttribute;
\t\t}
\t\telse if (value == 'indicated' && state.shape != null)
\t\t{
\t\t\tshape[field] = state.shape.indicatorColor;
\t\t}
\t\telse if (key != mxConstants.STYLE_FILLCOLOR &&
\t\t\tvalue == mxConstants.STYLE_FILLCOLOR &&
\t\t\tstate.shape != null)
\t\t{
\t\t\tshape[field] = state.style[mxConstants.STYLE_FILLCOLOR];
\t\t}
\t\telse if (key != mxConstants.STYLE_STROKECOLOR &&
\t\t\tvalue == mxConstants.STYLE_STROKECOLOR &&
\t\t\tstate.shape != null)
\t\t{
\t\t\tshape[field] = state.style[mxConstants.STYLE_STROKECOLOR];
\t\t}
\t
\t\tif (referenced != null)
\t\t{
\t\t\tvar rstate = graph.getView().getState(referenced);
\t\t\tshape[field] = null;
\t\t\t
\t\t\tif (rstate != null)
\t\t\t{
\t\t\t\tvar rshape = (key == mxConstants.STYLE_FONTCOLOR) ? rstate.text : rstate.shape;
\t\t\t\t
\t\t\t\tif (rshape != null && field != 'indicatorColor')
\t\t\t\t{
\t\t\t\t\tshape[field] = rshape[field];
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tshape[field] = rstate.style[key];
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: getLabelValue
 * 
 * Returns the value to be used for the label.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the label should be created.
 */
mxCellRenderer.prototype.getLabelValue = function(state)
{
\treturn state.view.graph.getLabel(state.cell);
};

/**
 * Function: createLabel
 * 
 * Creates the label for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the label should be created.
 */
mxCellRenderer.prototype.createLabel = function(state, value)
{
\tvar graph = state.view.graph;
\tvar isEdge = graph.getModel().isEdge(state.cell);
\t
\tif (state.style[mxConstants.STYLE_FONTSIZE] > 0 || state.style[mxConstants.STYLE_FONTSIZE] == null)
\t{
\t\t// Avoids using DOM node for empty labels
\t\tvar isForceHtml = (graph.isHtmlLabel(state.cell) || (value != null && mxUtils.isNode(value)));

\t\tstate.text = new this.defaultTextShape(value, new mxRectangle(),
\t\t\t\t(state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER),
\t\t\t\tgraph.getVerticalAlign(state),
\t\t\t\tstate.style[mxConstants.STYLE_FONTCOLOR],
\t\t\t\tstate.style[mxConstants.STYLE_FONTFAMILY],
\t\t\t\tstate.style[mxConstants.STYLE_FONTSIZE],
\t\t\t\tstate.style[mxConstants.STYLE_FONTSTYLE],
\t\t\t\tstate.style[mxConstants.STYLE_SPACING],
\t\t\t\tstate.style[mxConstants.STYLE_SPACING_TOP],
\t\t\t\tstate.style[mxConstants.STYLE_SPACING_RIGHT],
\t\t\t\tstate.style[mxConstants.STYLE_SPACING_BOTTOM],
\t\t\t\tstate.style[mxConstants.STYLE_SPACING_LEFT],
\t\t\t\tstate.style[mxConstants.STYLE_HORIZONTAL],
\t\t\t\tstate.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
\t\t\t\tstate.style[mxConstants.STYLE_LABEL_BORDERCOLOR],
\t\t\t\tgraph.isWrapping(state.cell) && graph.isHtmlLabel(state.cell),
\t\t\t\tgraph.isLabelClipped(state.cell),
\t\t\t\tstate.style[mxConstants.STYLE_OVERFLOW],
\t\t\t\tstate.style[mxConstants.STYLE_LABEL_PADDING],
\t\t\t\tmxUtils.getValue(state.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION));
\t\tstate.text.opacity = mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_OPACITY, 100);
\t\tstate.text.dialect = (isForceHtml) ? mxConstants.DIALECT_STRICTHTML : state.view.graph.dialect;
\t\tstate.text.style = state.style;
\t\tstate.text.state = state;
\t\tthis.initializeLabel(state, state.text);
\t\t
\t\t// Workaround for touch devices routing all events for a mouse gesture
\t\t// (down, move, up) via the initial DOM node. IE additionally redirects
\t\t// the event via the initial DOM node but the event source is the node
\t\t// under the mouse, so we need to check if this is the case and force
\t\t// getCellAt for the subsequent mouseMoves and the final mouseUp.
\t\tvar forceGetCell = false;
\t\t
\t\tvar getState = function(evt)
\t\t{
\t\t\tvar result = state;

\t\t\tif (mxClient.IS_TOUCH || forceGetCell)
\t\t\t{
\t\t\t\tvar x = mxEvent.getClientX(evt);
\t\t\t\tvar y = mxEvent.getClientY(evt);
\t\t\t\t
\t\t\t\t// Dispatches the drop event to the graph which
\t\t\t\t// consumes and executes the source function
\t\t\t\tvar pt = mxUtils.convertPoint(graph.container, x, y);
\t\t\t\tresult = graph.view.getState(graph.getCellAt(pt.x, pt.y));
\t\t\t}
\t\t\t
\t\t\treturn result;
\t\t};
\t\t
\t\t// TODO: Add handling for special touch device gestures
\t\tmxEvent.addGestureListeners(state.text.node,
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (this.isLabelEvent(state, evt))
\t\t\t\t{
\t\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
\t\t\t\t\tforceGetCell = graph.dialect != mxConstants.DIALECT_SVG &&
\t\t\t\t\t\tmxEvent.getSource(evt).nodeName == 'IMG';
\t\t\t\t}
\t\t\t}),
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (this.isLabelEvent(state, evt))
\t\t\t\t{
\t\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
\t\t\t\t}
\t\t\t}),
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (this.isLabelEvent(state, evt))
\t\t\t\t{
\t\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
\t\t\t\t\tforceGetCell = false;
\t\t\t\t}
\t\t\t})
\t\t);

\t\t// Uses double click timeout in mxGraph for quirks mode
\t\tif (graph.nativeDblClickEnabled)
\t\t{
\t\t\tmxEvent.addListener(state.text.node, 'dblclick',
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tif (this.isLabelEvent(state, evt))
\t\t\t\t\t{
\t\t\t\t\t\tgraph.dblClick(evt, state.cell);
\t\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t);
\t\t}
\t}
};

/**
 * Function: initializeLabel
 * 
 * Initiailzes the label with a suitable container.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label should be initialized.
 */
mxCellRenderer.prototype.initializeLabel = function(state, shape)
{
\tif (mxClient.IS_SVG && mxClient.NO_FO && shape.dialect != mxConstants.DIALECT_SVG)
\t{
\t\tshape.init(state.view.graph.container);
\t}
\telse
\t{
\t\tshape.init(state.view.getDrawPane());
\t}
};

/**
 * Function: createCellOverlays
 * 
 * Creates the actual shape for showing the overlay for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the overlay should be created.
 */
mxCellRenderer.prototype.createCellOverlays = function(state)
{
\tvar graph = state.view.graph;
\tvar overlays = graph.getCellOverlays(state.cell);
\tvar dict = null;
\t
\tif (overlays != null)
\t{
\t\tdict = new mxDictionary();
\t\t
\t\tfor (var i = 0; i < overlays.length; i++)
\t\t{
\t\t\tvar shape = (state.overlays != null) ? state.overlays.remove(overlays[i]) : null;
\t\t\t
\t\t\tif (shape == null)
\t\t\t{
\t\t\t\tvar tmp = new mxImageShape(new mxRectangle(), overlays[i].image.src);
\t\t\t\ttmp.dialect = state.view.graph.dialect;
\t\t\t\ttmp.preserveImageAspect = false;
\t\t\t\ttmp.overlay = overlays[i];
\t\t\t\tthis.initializeOverlay(state, tmp);
\t\t\t\tthis.installCellOverlayListeners(state, overlays[i], tmp);
\t
\t\t\t\tif (overlays[i].cursor != null)
\t\t\t\t{
\t\t\t\t\ttmp.node.style.cursor = overlays[i].cursor;
\t\t\t\t}
\t\t\t\t
\t\t\t\tdict.put(overlays[i], tmp);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdict.put(overlays[i], shape);
\t\t\t}
\t\t}
\t}
\t
\t// Removes unused
\tif (state.overlays != null)
\t{
\t\tstate.overlays.visit(function(id, shape)
\t\t{
\t\t\tshape.destroy();
\t\t});
\t}
\t
\tstate.overlays = dict;
};

/**
 * Function: initializeOverlay
 * 
 * Initializes the given overlay.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the overlay should be created.
 * overlay - <mxImageShape> that represents the overlay.
 */
mxCellRenderer.prototype.initializeOverlay = function(state, overlay)
{
\toverlay.init(state.view.getOverlayPane());
};

/**
 * Function: installOverlayListeners
 * 
 * Installs the listeners for the given <mxCellState>, <mxCellOverlay> and
 * <mxShape> that represents the overlay.
 */
mxCellRenderer.prototype.installCellOverlayListeners = function(state, overlay, shape)
{
\tvar graph  = state.view.graph;
\t
\tmxEvent.addListener(shape.node, 'click', function (evt)
\t{
\t\tif (graph.isEditing())
\t\t{
\t\t\tgraph.stopEditing(!graph.isInvokesStopCellEditing());
\t\t}
\t\t
\t\toverlay.fireEvent(new mxEventObject(mxEvent.CLICK,
\t\t\t\t'event', evt, 'cell', state.cell));
\t});
\t
\tmxEvent.addGestureListeners(shape.node,
\t\tfunction (evt)
\t\t{
\t\t\tmxEvent.consume(evt);
\t\t},
\t\tfunction (evt)
\t\t{
\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE,
\t\t\t\tnew mxMouseEvent(evt, state));
\t\t});
\t
\tif (mxClient.IS_TOUCH)
\t{
\t\tmxEvent.addListener(shape.node, 'touchend', function (evt)
\t\t{
\t\t\toverlay.fireEvent(new mxEventObject(mxEvent.CLICK,
\t\t\t\t\t'event', evt, 'cell', state.cell));
\t\t});
\t}
};

/**
 * Function: createControl
 * 
 * Creates the control for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the control should be created.
 */
mxCellRenderer.prototype.createControl = function(state)
{
\tvar graph = state.view.graph;
\tvar image = graph.getFoldingImage(state);
\t
\tif (graph.foldingEnabled && image != null)
\t{
\t\tif (state.control == null)
\t\t{
\t\t\tvar b = new mxRectangle(0, 0, image.width, image.height);
\t\t\tstate.control = new mxImageShape(b, image.src);
\t\t\tstate.control.preserveImageAspect = false;
\t\t\tstate.control.dialect = graph.dialect;

\t\t\tthis.initControl(state, state.control, true, this.createControlClickHandler(state));
\t\t}
\t}
\telse if (state.control != null)
\t{
\t\tstate.control.destroy();
\t\tstate.control = null;
\t}
};

/**
 * Function: createControlClickHandler
 * 
 * Hook for creating the click handler for the folding icon.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose control click handler should be returned.
 */
mxCellRenderer.prototype.createControlClickHandler = function(state)
{
\tvar graph = state.view.graph;
\t
\treturn mxUtils.bind(this, function (evt)
\t{
\t\tif (this.forceControlClickHandler || graph.isEnabled())
\t\t{
\t\t\tvar collapse = !graph.isCellCollapsed(state.cell);
\t\t\tgraph.foldCells(collapse, false, [state.cell], null, evt);
\t\t\tmxEvent.consume(evt);
\t\t}
\t});
};

/**
 * Function: initControl
 * 
 * Initializes the given control and returns the corresponding DOM node.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the control should be initialized.
 * control - <mxShape> to be initialized.
 * handleEvents - Boolean indicating if mousedown and mousemove should fire events via the graph.
 * clickHandler - Optional function to implement clicks on the control.
 */
mxCellRenderer.prototype.initControl = function(state, control, handleEvents, clickHandler)
{
\tvar graph = state.view.graph;
\t
\t// In the special case where the label is in HTML and the display is SVG the image
\t// should go into the graph container directly in order to be clickable. Otherwise
\t// it is obscured by the HTML label that overlaps the cell.
\tvar isForceHtml = graph.isHtmlLabel(state.cell) && mxClient.NO_FO &&
\t\tgraph.dialect == mxConstants.DIALECT_SVG;

\tif (isForceHtml)
\t{
\t\tcontrol.dialect = mxConstants.DIALECT_PREFERHTML;
\t\tcontrol.init(graph.container);
\t\tcontrol.node.style.zIndex = 1;
\t}
\telse
\t{
\t\tcontrol.init(state.view.getOverlayPane());
\t}

\tvar node = control.innerNode || control.node;
\t
\t// Workaround for missing click event on iOS is to check tolerance below
\tif (clickHandler != null && !mxClient.IS_IOS)
\t{
\t\tif (graph.isEnabled())
\t\t{
\t\t\tnode.style.cursor = 'pointer';
\t\t}
\t\t
\t\tmxEvent.addListener(node, 'click', clickHandler);
\t}
\t
\tif (handleEvents)
\t{
\t\tvar first = null;

\t\tmxEvent.addGestureListeners(node,
\t\t\tfunction (evt)
\t\t\t{
\t\t\t\tfirst = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
\t\t\t\tmxEvent.consume(evt);
\t\t\t},
\t\t\tfunction (evt)
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, state));
\t\t\t},
\t\t\tfunction (evt)
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, state));
\t\t\t\tmxEvent.consume(evt);
\t\t\t});
\t\t
\t\t// Uses capture phase for event interception to stop bubble phase
\t\tif (clickHandler != null && mxClient.IS_IOS)
\t\t{
\t\t\tnode.addEventListener('touchend', function(evt)
\t\t\t{
\t\t\t\tif (first != null)
\t\t\t\t{
\t\t\t\t\tvar tol = graph.tolerance;
\t\t\t\t\t
\t\t\t\t\tif (Math.abs(first.x - mxEvent.getClientX(evt)) < tol &&
\t\t\t\t\t\tMath.abs(first.y - mxEvent.getClientY(evt)) < tol)
\t\t\t\t\t{
\t\t\t\t\t\tclickHandler.call(clickHandler, evt);
\t\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}, true);
\t\t}
\t}
\t
\treturn node;
};

/**
 * Function: isShapeEvent
 * 
 * Returns true if the event is for the shape of the given state. This
 * implementation always returns true.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose shape fired the event.
 * evt - Mouse event which was fired.
 */
mxCellRenderer.prototype.isShapeEvent = function(state, evt)
{
\treturn true;
};

/**
 * Function: isLabelEvent
 * 
 * Returns true if the event is for the label of the given state. This
 * implementation always returns true.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label fired the event.
 * evt - Mouse event which was fired.
 */
mxCellRenderer.prototype.isLabelEvent = function(state, evt)
{
\treturn true;
};

/**
 * Function: installListeners
 * 
 * Installs the event listeners for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the event listeners should be isntalled.
 */
mxCellRenderer.prototype.installListeners = function(state)
{
\tvar graph = state.view.graph;

\t// Workaround for touch devices routing all events for a mouse
\t// gesture (down, move, up) via the initial DOM node. Same for
\t// HTML images in all IE versions (VML images are working).
\tvar getState = function(evt)
\t{
\t\tvar result = state;
\t\t
\t\tif ((graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG') || mxClient.IS_TOUCH)
\t\t{
\t\t\tvar x = mxEvent.getClientX(evt);
\t\t\tvar y = mxEvent.getClientY(evt);
\t\t\t
\t\t\t// Dispatches the drop event to the graph which
\t\t\t// consumes and executes the source function
\t\t\tvar pt = mxUtils.convertPoint(graph.container, x, y);
\t\t\tresult = graph.view.getState(graph.getCellAt(pt.x, pt.y));
\t\t}
\t\t
\t\treturn result;
\t};

\tmxEvent.addGestureListeners(state.shape.node,
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isShapeEvent(state, evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
\t\t\t}
\t\t}),
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isShapeEvent(state, evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t}),
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isShapeEvent(state, evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t})
\t);
\t
\t// Uses double click timeout in mxGraph for quirks mode
\tif (graph.nativeDblClickEnabled)
\t{
\t\tmxEvent.addListener(state.shape.node, 'dblclick',
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tif (this.isShapeEvent(state, evt))
\t\t\t\t{
\t\t\t\t\tgraph.dblClick(evt, state.cell);
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t}
\t\t\t})
\t\t);
\t}
};

/**
 * Function: redrawLabel
 * 
 * Redraws the label for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label should be redrawn.
 */
mxCellRenderer.prototype.redrawLabel = function(state, forced)
{
\tvar graph = state.view.graph;
\tvar value = this.getLabelValue(state);
\tvar wrapping = graph.isWrapping(state.cell);
\tvar clipping = graph.isLabelClipped(state.cell);
\tvar isForceHtml = (state.view.graph.isHtmlLabel(state.cell) || (value != null && mxUtils.isNode(value)));
\tvar dialect = (isForceHtml) ? mxConstants.DIALECT_STRICTHTML : state.view.graph.dialect;
\tvar overflow = state.style[mxConstants.STYLE_OVERFLOW] || 'visible';

\tif (state.text != null && (state.text.wrap != wrapping || state.text.clipped != clipping ||
\t\tstate.text.overflow != overflow || state.text.dialect != dialect))
\t{
\t\tstate.text.destroy();
\t\tstate.text = null;
\t}
\t
\tif (state.text == null && value != null && (mxUtils.isNode(value) || value.length > 0))
\t{
\t\tthis.createLabel(state, value);
\t}
\telse if (state.text != null && (value == null || value.length == 0))
\t{
\t\tstate.text.destroy();
\t\tstate.text = null;
\t}

\tif (state.text != null)
\t{
\t\t// Forced is true if the style has changed, so to get the updated
\t\t// result in getLabelBounds we apply the new style to the shape
\t\tif (forced)
\t\t{
\t\t\t// Checks if a full repaint is needed
\t\t\tif (state.text.lastValue != null && this.isTextShapeInvalid(state, state.text))
\t\t\t{
\t\t\t\t// Forces a full repaint
\t\t\t\tstate.text.lastValue = null;
\t\t\t}
\t\t\t
\t\t\tstate.text.resetStyles();
\t\t\tstate.text.apply(state);
\t\t\t
\t\t\t// Special case where value is obtained via hook in graph
\t\t\tstate.text.valign = graph.getVerticalAlign(state);
\t\t}
\t\t
\t\tvar bounds = this.getLabelBounds(state);
\t\tvar nextScale = this.getTextScale(state);
\t\tthis.resolveColor(state, 'color', mxConstants.STYLE_FONTCOLOR);
\t\t
\t\tif (forced || state.text.value != value || state.text.isWrapping != wrapping ||
\t\t\tstate.text.overflow != overflow || state.text.isClipping != clipping ||
\t\t\tstate.text.scale != nextScale || state.text.dialect != dialect ||
\t\t\tstate.text.bounds == null || !state.text.bounds.equals(bounds))
\t\t{
\t\t\tstate.text.dialect = dialect;
\t\t\tstate.text.value = value;
\t\t\tstate.text.bounds = bounds;
\t\t\tstate.text.scale = nextScale;
\t\t\tstate.text.wrap = wrapping;
\t\t\tstate.text.clipped = clipping;
\t\t\tstate.text.overflow = overflow;
\t\t\t
\t\t\t// Preserves visible state
\t\t\tvar vis = state.text.node.style.visibility;
\t\t\tthis.redrawLabelShape(state.text);
\t\t\tstate.text.node.style.visibility = vis;
\t\t}
\t}
};

/**
 * Function: isTextShapeInvalid
 * 
 * Returns true if the style for the text shape has changed.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label should be checked.
 * shape - <mxText> shape to be checked.
 */
mxCellRenderer.prototype.isTextShapeInvalid = function(state, shape)
{
\tfunction check(property, stylename, defaultValue)
\t{
\t\tvar result = false;
\t\t
\t\t// Workaround for spacing added to directional spacing
\t\tif (stylename == 'spacingTop' || stylename == 'spacingRight' ||
\t\t\tstylename == 'spacingBottom' || stylename == 'spacingLeft')
\t\t{
\t\t\tresult = parseFloat(shape[property]) - parseFloat(shape.spacing) !=
\t\t\t\t(state.style[stylename] || defaultValue);
\t\t}
\t\telse
\t\t{
\t\t\tresult = shape[property] != (state.style[stylename] || defaultValue);
\t\t}
\t\t
\t\treturn result;
\t};

\treturn check('fontStyle', mxConstants.STYLE_FONTSTYLE, mxConstants.DEFAULT_FONTSTYLE) ||
\t\tcheck('family', mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY) ||
\t\tcheck('size', mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE) ||
\t\tcheck('color', mxConstants.STYLE_FONTCOLOR, 'black') ||
\t\tcheck('align', mxConstants.STYLE_ALIGN, '') ||
\t\tcheck('valign', mxConstants.STYLE_VERTICAL_ALIGN, '') ||
\t\tcheck('spacing', mxConstants.STYLE_SPACING, 2) ||
\t\tcheck('spacingTop', mxConstants.STYLE_SPACING_TOP, 0) ||
\t\tcheck('spacingRight', mxConstants.STYLE_SPACING_RIGHT, 0) ||
\t\tcheck('spacingBottom', mxConstants.STYLE_SPACING_BOTTOM, 0) ||
\t\tcheck('spacingLeft', mxConstants.STYLE_SPACING_LEFT, 0) ||
\t\tcheck('horizontal', mxConstants.STYLE_HORIZONTAL, true) ||
\t\tcheck('background', mxConstants.STYLE_LABEL_BACKGROUNDCOLOR) ||
\t\tcheck('border', mxConstants.STYLE_LABEL_BORDERCOLOR) ||
\t\tcheck('opacity', mxConstants.STYLE_TEXT_OPACITY, 100) ||
\t\tcheck('textDirection', mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
};

/**
 * Function: redrawLabelShape
 * 
 * Called to invoked redraw on the given text shape.
 * 
 * Parameters:
 * 
 * shape - <mxText> shape to be redrawn.
 */
mxCellRenderer.prototype.redrawLabelShape = function(shape)
{
\tshape.redraw();
};

/**
 * Function: getTextScale
 * 
 * Returns the scaling used for the label of the given state
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label scale should be returned.
 */
mxCellRenderer.prototype.getTextScale = function(state)
{
\treturn state.view.scale;
};

/**
 * Function: getLabelBounds
 * 
 * Returns the bounds to be used to draw the label of the given state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label bounds should be returned.
 */
mxCellRenderer.prototype.getLabelBounds = function(state)
{
\tvar graph = state.view.graph;
\tvar scale = state.view.scale;
\tvar isEdge = graph.getModel().isEdge(state.cell);
\tvar bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y);

\tif (isEdge)
\t{
\t\tvar spacing = state.text.getSpacing();
\t\tbounds.x += spacing.x * scale;
\t\tbounds.y += spacing.y * scale;
\t\t
\t\tvar geo = graph.getCellGeometry(state.cell);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tbounds.width = Math.max(0, geo.width * scale);
\t\t\tbounds.height = Math.max(0, geo.height * scale);
\t\t}
\t}
\telse
\t{
\t\t// Inverts label position
\t\tif (state.text.isPaintBoundsInverted())
\t\t{
\t\t\tvar tmp = bounds.x;
\t\t\tbounds.x = bounds.y;
\t\t\tbounds.y = tmp;
\t\t}
\t\t
\t\tbounds.x += state.x;
\t\tbounds.y += state.y;
\t\t
\t\t// Minimum of 1 fixes alignment bug in HTML labels
\t\tbounds.width = Math.max(1, state.width);
\t\tbounds.height = Math.max(1, state.height);
\t}

\tif (state.text.isPaintBoundsInverted())
\t{
\t\t// Rotates around center of state
\t\tvar t = (state.width - state.height) / 2;
\t\tbounds.x += t;
\t\tbounds.y -= t;
\t\tvar tmp = bounds.width;
\t\tbounds.width = bounds.height;
\t\tbounds.height = tmp;
\t}
\t
\t// Shape can modify its label bounds
\tif (state.shape != null)
\t{
\t\tvar hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t\tvar vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
\t\t
\t\tif (hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE)
\t\t{
\t\t\tbounds = state.shape.getLabelBounds(bounds);
\t\t}
\t}
\t
\t// Label width style overrides actual label width
\tvar lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
\t
\tif (lw != null)
\t{
\t\tbounds.width = parseFloat(lw) * scale;
\t}
\t
\tif (!isEdge)
\t{
\t\tthis.rotateLabelBounds(state, bounds);
\t}
\t
\treturn bounds;
};

/**
 * Function: rotateLabelBounds
 * 
 * Adds the shape rotation to the given label bounds and
 * applies the alignment and offsets.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label bounds should be rotated.
 * bounds - <mxRectangle> the rectangle to be rotated.
 */
mxCellRenderer.prototype.rotateLabelBounds = function(state, bounds)
{
\tbounds.y -= state.text.margin.y * bounds.height;
\tbounds.x -= state.text.margin.x * bounds.width;
\t
\tif (!this.legacySpacing || (state.style[mxConstants.STYLE_OVERFLOW] != 'fill' && state.style[mxConstants.STYLE_OVERFLOW] != 'width'))
\t{
\t\tvar s = state.view.scale;
\t\tvar spacing = state.text.getSpacing();
\t\tbounds.x += spacing.x * s;
\t\tbounds.y += spacing.y * s;
\t\t
\t\tvar hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
\t\tvar vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
\t\tvar lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
\t\t
\t\tbounds.width = Math.max(0, bounds.width - ((hpos == mxConstants.ALIGN_CENTER && lw == null) ? (state.text.spacingLeft * s + state.text.spacingRight * s) : 0));
\t\tbounds.height = Math.max(0, bounds.height - ((vpos == mxConstants.ALIGN_MIDDLE) ? (state.text.spacingTop * s + state.text.spacingBottom * s) : 0));
\t}

\tvar theta = state.text.getTextRotation();

\t// Only needed if rotated around another center
\tif (theta != 0 && state != null && state.view.graph.model.isVertex(state.cell))
\t{
\t\tvar cx = state.getCenterX();
\t\tvar cy = state.getCenterY();
\t\t
\t\tif (bounds.x != cx || bounds.y != cy)
\t\t{
\t\t\tvar rad = theta * (Math.PI / 180);
\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(bounds.x, bounds.y),
\t\t\t\t\tMath.cos(rad), Math.sin(rad), new mxPoint(cx, cy));
\t\t\t
\t\t\tbounds.x = pt.x;
\t\t\tbounds.y = pt.y;
\t\t}
\t}
};

/**
 * Function: redrawCellOverlays
 * 
 * Redraws the overlays for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose overlays should be redrawn.
 */
mxCellRenderer.prototype.redrawCellOverlays = function(state, forced)
{
\tthis.createCellOverlays(state);

\tif (state.overlays != null)
\t{
\t\tvar 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);
\t\t
\t\tstate.overlays.visit(function(id, shape)
\t\t{
\t\t\tvar bounds = shape.overlay.getBounds(state);
\t\t
\t\t\tif (!state.view.graph.getModel().isEdge(state.cell))
\t\t\t{
\t\t\t\tif (state.shape != null && rot != 0)
\t\t\t\t{
\t\t\t\t\tvar cx = bounds.getCenterX();
\t\t\t\t\tvar cy = bounds.getCenterY();

\t\t\t\t\tvar point = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin,
\t\t\t        \t\tnew mxPoint(state.getCenterX(), state.getCenterY()));

\t\t\t        cx = point.x;
\t\t\t        cy = point.y;
\t\t\t        bounds.x = Math.round(cx - bounds.width / 2);
\t\t\t        bounds.y = Math.round(cy - bounds.height / 2);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (forced || shape.bounds == null || shape.scale != state.view.scale ||
\t\t\t\t!shape.bounds.equals(bounds))
\t\t\t{
\t\t\t\tshape.bounds = bounds;
\t\t\t\tshape.scale = state.view.scale;
\t\t\t\tshape.redraw();
\t\t\t}
\t\t});
\t}
};

/**
 * Function: redrawControl
 * 
 * Redraws the control for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose control should be redrawn.
 */
mxCellRenderer.prototype.redrawControl = function(state, forced)
{
\tvar image = state.view.graph.getFoldingImage(state);
\t
\tif (state.control != null && image != null)
\t{
\t\tvar bounds = this.getControlBounds(state, image.width, image.height);
\t\tvar r = (this.legacyControlPosition) ?
\t\t\t\tmxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0) :
\t\t\t\tstate.shape.getTextRotation();
\t\tvar s = state.view.scale;
\t\t
\t\tif (forced || state.control.scale != s || !state.control.bounds.equals(bounds) ||
\t\t\tstate.control.rotation != r)
\t\t{
\t\t\tstate.control.rotation = r;
\t\t\tstate.control.bounds = bounds;
\t\t\tstate.control.scale = s;
\t\t\t
\t\t\tstate.control.redraw();
\t\t}
\t}
};

/**
 * Function: getControlBounds
 * 
 * Returns the bounds to be used to draw the control (folding icon) of the
 * given state.
 */
mxCellRenderer.prototype.getControlBounds = function(state, w, h)
{
\tif (state.control != null)
\t{
\t\tvar s = state.view.scale;
\t\tvar cx = state.getCenterX();
\t\tvar cy = state.getCenterY();
\t
\t\tif (!state.view.graph.getModel().isEdge(state.cell))
\t\t{
\t\t\tcx = state.x + w * s;
\t\t\tcy = state.y + h * s;
\t\t\t
\t\t\tif (state.shape != null)
\t\t\t{
\t\t\t\t// TODO: Factor out common code
\t\t\t\tvar rot = state.shape.getShapeRotation();
\t\t\t\t
\t\t\t\tif (this.legacyControlPosition)
\t\t\t\t{
\t\t\t\t\trot = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tif (state.shape.isPaintBoundsInverted())
\t\t\t\t\t{
\t\t\t\t\t\tvar t = (state.width - state.height) / 2;
\t\t\t\t\t\tcx += t;
\t\t\t\t\t\tcy -= t;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (rot != 0)
\t\t\t\t{
\t\t\t        var rad = mxUtils.toRadians(rot);
\t\t\t        var cos = Math.cos(rad);
\t\t\t        var sin = Math.sin(rad);
\t\t\t        
\t\t\t        var point = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin,
\t\t\t        \t\tnew mxPoint(state.getCenterX(), state.getCenterY()));
\t\t\t        cx = point.x;
\t\t\t        cy = point.y;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn (state.view.graph.getModel().isEdge(state.cell)) ? 
\t\t\tnew mxRectangle(Math.round(cx - w / 2 * s), Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s))
\t\t\t: new mxRectangle(Math.round(cx - w / 2 * s), Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s));
\t}
\t
\treturn null;
};

/**
 * Function: insertStateAfter
 * 
 * Inserts the given array of <mxShapes> after the given nodes in the DOM.
 * 
 * Parameters:
 * 
 * shapes - Array of <mxShapes> to be inserted.
 * node - Node in <drawPane> after which the shapes should be inserted.
 * htmlNode - Node in the graph container after which the shapes should be inserted that
 * will not go into the <drawPane> (eg. HTML labels without foreignObjects).
 */
mxCellRenderer.prototype.insertStateAfter = function(state, node, htmlNode)
{
\tvar shapes = this.getShapesForState(state);
\t
\tfor (var i = 0; i < shapes.length; i++)
\t{
\t\tif (shapes[i] != null && shapes[i].node != null)
\t\t{
\t\t\tvar html = shapes[i].node.parentNode != state.view.getDrawPane() &&
\t\t\t\tshapes[i].node.parentNode != state.view.getOverlayPane();
\t\t\tvar temp = (html) ? htmlNode : node;
\t\t\t
\t\t\tif (temp != null && temp.nextSibling != shapes[i].node)
\t\t\t{
\t\t\t\tif (temp.nextSibling == null)
\t\t\t\t{
\t\t\t\t\ttemp.parentNode.appendChild(shapes[i].node);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\ttemp.parentNode.insertBefore(shapes[i].node, temp.nextSibling);
\t\t\t\t}
\t\t\t}
\t\t\telse if (temp == null)
\t\t\t{
\t\t\t\t// Special case: First HTML node should be first sibling after canvas
\t\t\t\tif (shapes[i].node.parentNode == state.view.graph.container)
\t\t\t\t{
\t\t\t\t\tvar canvas = state.view.canvas;
\t\t\t\t\t
\t\t\t\t\twhile (canvas != null && canvas.parentNode != state.view.graph.container)
\t\t\t\t\t{
\t\t\t\t\t\tcanvas = canvas.parentNode;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (canvas != null && canvas.nextSibling != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (canvas.nextSibling != shapes[i].node)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tshapes[i].node.parentNode.insertBefore(shapes[i].node, canvas.nextSibling);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tshapes[i].node.parentNode.appendChild(shapes[i].node);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (shapes[i].node.parentNode != null &&
\t\t\t\t\tshapes[i].node.parentNode.firstChild != null &&
\t\t\t\t\tshapes[i].node.parentNode.firstChild != shapes[i].node)
\t\t\t\t{
\t\t\t\t\t// Inserts the node as the first child of the parent to implement the order
\t\t\t\t\tshapes[i].node.parentNode.insertBefore(shapes[i].node, shapes[i].node.parentNode.firstChild);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (html)
\t\t\t{
\t\t\t\thtmlNode = shapes[i].node;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tnode = shapes[i].node;
\t\t\t}
\t\t}
\t}

\treturn [node, htmlNode];
};

/**
 * Function: getShapesForState
 * 
 * Returns the <mxShapes> for the given cell state in the order in which they should
 * appear in the DOM.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose shapes should be returned.
 */
mxCellRenderer.prototype.getShapesForState = function(state)
{
\treturn [state.shape, state.text, state.control];
};

/**
 * Function: redraw
 * 
 * Updates the bounds or points and scale of the shapes for the given cell
 * state. This is called in mxGraphView.validatePoints as the last step of
 * updating all cells.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the shapes should be updated.
 * force - Optional boolean that specifies if the cell should be reconfiured
 * and redrawn without any additional checks.
 * rendering - Optional boolean that specifies if the cell should actually
 * be drawn into the DOM. If this is false then redraw and/or reconfigure
 * will not be called on the shape.
 */
mxCellRenderer.prototype.redraw = function(state, force, rendering)
{
\tvar shapeChanged = this.redrawShape(state, force, rendering);

\tif (state.shape != null && (rendering == null || rendering))
\t{
\t\tthis.redrawLabel(state, shapeChanged);
\t\tthis.redrawCellOverlays(state, shapeChanged);
\t\tthis.redrawControl(state, shapeChanged);
\t}
};

/**
 * Function: redrawShape
 * 
 * Redraws the shape for the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose label should be redrawn.
 */
mxCellRenderer.prototype.redrawShape = function(state, force, rendering)
{
\tvar model = state.view.graph.model;
\tvar shapeChanged = false;

\t// Forces creation of new shape if shape style has changed
\tif (state.shape != null && state.shape.style != null && state.style != null &&
\t\tstate.shape.style[mxConstants.STYLE_SHAPE] != state.style[mxConstants.STYLE_SHAPE])
\t{
\t\tstate.shape.destroy();
\t\tstate.shape = null;
\t}
\t
\tif (state.shape == null && state.view.graph.container != null &&
\t\tstate.cell != state.view.currentRoot &&
\t\t(model.isVertex(state.cell) || model.isEdge(state.cell)))
\t{
\t\tstate.shape = this.createShape(state);
\t\t
\t\tif (state.shape != null)
\t\t{
\t\t\tstate.shape.minSvgStrokeWidth = this.minSvgStrokeWidth;
\t\t\tstate.shape.antiAlias = this.antiAlias;
\t
\t\t\tthis.createIndicatorShape(state);
\t\t\tthis.initializeShape(state);
\t\t\tthis.createCellOverlays(state);
\t\t\tthis.installListeners(state);
\t\t\t
\t\t\t// Forces a refresh of the handler if one exists
\t\t\tstate.view.graph.selectionCellsHandler.updateHandler(state);
\t\t}
\t}
\telse if (!force && state.shape != null && (!mxUtils.equalEntries(state.shape.style,
\t\tstate.style) || this.checkPlaceholderStyles(state)))
\t{
\t\tstate.shape.resetStyles();
\t\tthis.configureShape(state);
\t\t// LATER: Ignore update for realtime to fix reset of current gesture
\t\tstate.view.graph.selectionCellsHandler.updateHandler(state);
\t\tforce = true;
\t}
\t
\t// Updates indicator shape
\tif (state.shape != null && state.shape.indicatorShape !=
\t\tthis.getShape(state.view.graph.getIndicatorShape(state)))
\t{
\t\tif (state.shape.indicator != null)
\t\t{
\t\t\tstate.shape.indicator.destroy();
\t\t\tstate.shape.indicator = null;
\t\t}
\t\t
\t\tthis.createIndicatorShape(state);
\t\t
\t\tif (state.shape.indicatorShape != null)
\t\t{
\t\t\tstate.shape.indicator = new state.shape.indicatorShape();
\t\t\tstate.shape.indicator.dialect = state.shape.dialect;
\t\t\tstate.shape.indicator.init(state.node);
\t\t\tforce = true;
\t\t}
\t}

\tif (state.shape != null)
\t{
\t\t// Handles changes of the collapse icon
\t\tthis.createControl(state);
\t\t
\t\t// Redraws the cell if required, ignores changes to bounds if points are
\t\t// defined as the bounds are updated for the given points inside the shape
\t\tif (force || this.isShapeInvalid(state, state.shape))
\t\t{
\t\t\tif (state.absolutePoints != null)
\t\t\t{
\t\t\t\tstate.shape.points = state.absolutePoints.slice();
\t\t\t\tstate.shape.bounds = null;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tstate.shape.points = null;
\t\t\t\tstate.shape.bounds = new mxRectangle(state.x, state.y, state.width, state.height);
\t\t\t}

\t\t\tstate.shape.scale = state.view.scale;
\t\t\t
\t\t\tif (rendering == null || rendering)
\t\t\t{
\t\t\t\tthis.doRedrawShape(state);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tstate.shape.updateBoundingBox();
\t\t\t}
\t\t\t
\t\t\tshapeChanged = true;
\t\t}
\t}

\treturn shapeChanged;
};

/**
 * Function: doRedrawShape
 * 
 * Invokes redraw on the shape of the given state.
 */
mxCellRenderer.prototype.doRedrawShape = function(state)
{
\tstate.shape.redraw();
};

/**
 * Function: isShapeInvalid
 * 
 * Returns true if the given shape must be repainted.
 */
mxCellRenderer.prototype.isShapeInvalid = function(state, shape)
{
\treturn shape.bounds == null || shape.scale != state.view.scale ||
\t\t(state.absolutePoints == null && !shape.bounds.equals(state)) ||
\t\t(state.absolutePoints != null && !mxUtils.equalPoints(shape.points, state.absolutePoints))
};

/**
 * Function: destroy
 * 
 * Destroys the shapes associated with the given cell state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> for which the shapes should be destroyed.
 */
mxCellRenderer.prototype.destroy = function(state)
{
\tif (state.shape != null)
\t{
\t\tif (state.text != null)
\t\t{\t\t
\t\t\tstate.text.destroy();
\t\t\tstate.text = null;
\t\t}
\t\t
\t\tif (state.overlays != null)
\t\t{
\t\t\tstate.overlays.visit(function(id, shape)
\t\t\t{
\t\t\t\tshape.destroy();
\t\t\t});
\t\t\t
\t\t\tstate.overlays = null;
\t\t}

\t\tif (state.control != null)
\t\t{
\t\t\tstate.control.destroy();
\t\t\tstate.control = null;
\t\t}
\t\t
\t\tstate.shape.destroy();
\t\tstate.shape = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxEdgeStyle =
{
\t/**
\t * Class: mxEdgeStyle
\t * 
\t * Provides various edge styles to be used as the values for
\t * <mxConstants.STYLE_EDGE> in a cell style.
\t *
\t * Example:
\t * 
\t * (code)
\t * var style = stylesheet.getDefaultEdgeStyle();
\t * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;
\t * (end)
\t * 
\t * Sets the default edge style to <ElbowConnector>.
\t * 
\t * Custom edge style:
\t * 
\t * To write a custom edge style, a function must be added to the mxEdgeStyle
\t * object as follows:
\t * 
\t * (code)
\t * mxEdgeStyle.MyStyle = function(state, source, target, points, result)
\t * {
\t *   if (source != null && target != null)
\t *   {
\t *     var pt = new mxPoint(target.getCenterX(), source.getCenterY());
\t * 
\t *     if (mxUtils.contains(source, pt.x, pt.y))
\t *     {
\t *       pt.y = source.y + source.height;
\t *     }
\t * 
\t *     result.push(pt);
\t *   }
\t * };
\t * (end)
\t * 
\t * In the above example, a right angle is created using a point on the
\t * horizontal center of the target vertex and the vertical center of the source
\t * vertex. The code checks if that point intersects the source vertex and makes
\t * the edge straight if it does. The point is then added into the result array,
\t * which acts as the return value of the function.
\t *
\t * The new edge style should then be registered in the <mxStyleRegistry> as follows:
\t * (code)
\t * mxStyleRegistry.putValue('myEdgeStyle', mxEdgeStyle.MyStyle);
\t * (end)
\t * 
\t * The custom edge style above can now be used in a specific edge as follows:
\t * 
\t * (code)
\t * model.setStyle(edge, 'edgeStyle=myEdgeStyle');
\t * (end)
\t * 
\t * Note that the key of the <mxStyleRegistry> entry for the function should
\t * be used in string values, unless <mxGraphView.allowEval> is true, in
\t * which case you can also use mxEdgeStyle.MyStyle for the value in the
\t * cell style above.
\t * 
\t * Or it can be used for all edges in the graph as follows:
\t * 
\t * (code)
\t * var style = graph.getStylesheet().getDefaultEdgeStyle();
\t * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.MyStyle;
\t * (end)
\t * 
\t * Note that the object can be used directly when programmatically setting
\t * the value, but the key in the <mxStyleRegistry> should be used when
\t * setting the value via a key, value pair in a cell style.
\t * 
\t * Function: EntityRelation
\t * 
\t * Implements an entity relation style for edges (as used in database
\t * schema diagrams). At the time the function is called, the result
\t * array contains a placeholder (null) for the first absolute point,
\t * that is, the point where the edge and source terminal are connected.
\t * The implementation of the style then adds all intermediate waypoints
\t * except for the last point, that is, the connection point between the
\t * edge and the target terminal. The first ant the last point in the
\t * result array are then replaced with mxPoints that take into account
\t * the terminal's perimeter and next point on the edge.
\t *
\t * Parameters:
\t * 
\t * state - <mxCellState> that represents the edge to be updated.
\t * source - <mxCellState> that represents the source terminal.
\t * target - <mxCellState> that represents the target terminal.
\t * points - List of relative control points.
\t * result - Array of <mxPoints> that represent the actual points of the
\t * edge.
\t */
\t EntityRelation: function(state, source, target, points, result)
\t {
\t\tvar view = state.view;
\t \tvar graph = view.graph;
\t \tvar segment = mxUtils.getValue(state.style,
\t \t\t\tmxConstants.STYLE_SEGMENT,
\t \t\t\tmxConstants.ENTITY_SEGMENT) * view.scale;
\t \t
\t\tvar pts = state.absolutePoints;
\t\tvar p0 = pts[0];
\t\tvar pe = pts[pts.length-1];

\t \tvar isSourceLeft = false;
\t \t
\t \tif (source != null)
\t \t{
 \t\t\tvar sourceGeometry = graph.getCellGeometry(source.cell);
\t
\t\t \tif (sourceGeometry.relative)
\t\t \t{
\t\t \t\tisSourceLeft = sourceGeometry.x <= 0.5;
\t\t \t}
\t\t \telse if (target != null)
\t\t \t{
\t\t \t\tisSourceLeft = ((pe != null) ? pe.x : target.x + target.width) < ((p0 != null) ? p0.x : source.x);
\t\t \t}
\t \t}

\t\tif (p0 != null)
\t\t{
\t\t\tsource = new mxCellState();
\t\t\tsource.x = p0.x;
\t\t\tsource.y = p0.y;
\t\t}
\t\telse if (source != null)
\t\t{
\t\t\tvar constraint = mxUtils.getPortConstraints(source, state, true, mxConstants.DIRECTION_MASK_NONE);
\t\t\t
\t\t\tif (constraint != mxConstants.DIRECTION_MASK_NONE && constraint != mxConstants.DIRECTION_MASK_WEST +
\t\t\t\tmxConstants.DIRECTION_MASK_EAST)
\t\t\t{
\t\t\t\tisSourceLeft = constraint == mxConstants.DIRECTION_MASK_WEST;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\treturn;
\t\t}
\t \t
\t \tvar isTargetLeft = true;
\t \t
\t \tif (target != null)
\t \t{
\t\t \tvar targetGeometry = graph.getCellGeometry(target.cell);
\t
\t\t \tif (targetGeometry.relative)
\t\t \t{
\t\t \t\tisTargetLeft = targetGeometry.x <= 0.5;
\t\t \t}
\t\t \telse if (source != null)
\t\t \t{
\t\t \t\tisTargetLeft = ((p0 != null) ? p0.x : source.x + source.width) < ((pe != null) ? pe.x : target.x);
\t\t \t}
\t \t}
\t\t
\t\tif (pe != null)
\t\t{
\t\t\ttarget = new mxCellState();
\t\t\ttarget.x = pe.x;
\t\t\ttarget.y = pe.y;
\t\t}
\t\telse if (target != null)
\t \t{
\t\t\tvar constraint = mxUtils.getPortConstraints(target, state, false, mxConstants.DIRECTION_MASK_NONE);

\t\t\tif (constraint != mxConstants.DIRECTION_MASK_NONE && constraint != mxConstants.DIRECTION_MASK_WEST +
\t\t\t\tmxConstants.DIRECTION_MASK_EAST)
\t\t\t{
\t\t\t\tisTargetLeft = constraint == mxConstants.DIRECTION_MASK_WEST;
\t\t\t}
\t \t}
\t\t
\t\tif (source != null && target != null)
\t\t{
\t\t\tvar x0 = (isSourceLeft) ? source.x : source.x + source.width;
\t\t\tvar y0 = view.getRoutingCenterY(source);
\t\t\t
\t\t\tvar xe = (isTargetLeft) ? target.x : target.x + target.width;
\t\t\tvar ye = view.getRoutingCenterY(target);
\t
\t\t\tvar seg = segment;
\t
\t\t\tvar dx = (isSourceLeft) ? -seg : seg;
\t\t\tvar dep = new mxPoint(x0 + dx, y0);
\t\t\t\t\t
\t\t\tdx = (isTargetLeft) ? -seg : seg;
\t\t\tvar arr = new mxPoint(xe + dx, ye);
\t\t\t
\t\t\t// Adds intermediate points if both go out on same side
\t\t\tif (isSourceLeft == isTargetLeft)
\t\t\t{
\t\t\t\tvar x = (isSourceLeft) ?
\t\t\t\t\tMath.min(x0, xe)-segment :
\t\t\t\t\tMath.max(x0, xe)+segment;
\t
\t\t\t\tresult.push(new mxPoint(x, y0));
\t\t\t\tresult.push(new mxPoint(x, ye));
\t\t\t}
\t\t\telse if ((dep.x < arr.x) == isSourceLeft)
\t\t\t{
\t\t\t\tvar midY = y0 + (ye - y0) / 2;
\t
\t\t\t\tresult.push(dep);
\t\t\t\tresult.push(new mxPoint(dep.x, midY));
\t\t\t\tresult.push(new mxPoint(arr.x, midY));
\t\t\t\tresult.push(arr);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.push(dep);
\t\t\t\tresult.push(arr);
\t\t\t}
\t\t}
\t },

\t /**
\t * Function: Loop
\t * 
\t * Implements a self-reference, aka. loop.
\t */
\tLoop: function(state, source, target, points, result)
\t{
\t\tvar pts = state.absolutePoints;
\t\t
\t\tvar p0 = pts[0];
\t\tvar pe = pts[pts.length-1];

\t\tif (p0 != null && pe != null)
\t\t{
\t\t\tif (points != null && points.length > 0)
\t\t\t{
\t\t\t\tfor (var i = 0; i < points.length; i++)
\t\t\t\t{
\t\t\t\t\tvar pt = points[i];
\t\t\t\t\tpt = state.view.transformControlPoint(state, pt);
\t\t\t\t\tresult.push(new mxPoint(pt.x, pt.y));
\t\t\t\t}
\t\t\t}

\t\t\treturn;
\t\t}
\t\t
\t\tif (source != null)
\t\t{
\t\t\tvar view = state.view;
\t\t\tvar graph = view.graph;
\t\t\tvar pt = (points != null && points.length > 0) ? points[0] : null;

\t\t\tif (pt != null)
\t\t\t{
\t\t\t\tpt = view.transformControlPoint(state, pt);
\t\t\t\t\t
\t\t\t\tif (mxUtils.contains(source, pt.x, pt.y))
\t\t\t\t{
\t\t\t\t\tpt = null;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar x = 0;
\t\t\tvar dx = 0;
\t\t\tvar y = 0;
\t\t\tvar dy = 0;
\t\t\t
\t\t \tvar seg = mxUtils.getValue(state.style, mxConstants.STYLE_SEGMENT,
\t\t \t\tgraph.gridSize) * view.scale;
\t\t\tvar dir = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION,
\t\t\t\tmxConstants.DIRECTION_WEST);
\t\t\t
\t\t\tif (dir == mxConstants.DIRECTION_NORTH ||
\t\t\t\tdir == mxConstants.DIRECTION_SOUTH)
\t\t\t{
\t\t\t\tx = view.getRoutingCenterX(source);
\t\t\t\tdx = seg;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\ty = view.getRoutingCenterY(source);
\t\t\t\tdy = seg;
\t\t\t}
\t\t\t
\t\t\tif (pt == null ||
\t\t\t\tpt.x < source.x ||
\t\t\t\tpt.x > source.x + source.width)
\t\t\t{
\t\t\t\tif (pt != null)
\t\t\t\t{
\t\t\t\t\tx = pt.x;
\t\t\t\t\tdy = Math.max(Math.abs(y - pt.y), dy);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tif (dir == mxConstants.DIRECTION_NORTH)
\t\t\t\t\t{
\t\t\t\t\t\ty = source.y - 2 * dx;
\t\t\t\t\t}
\t\t\t\t\telse if (dir == mxConstants.DIRECTION_SOUTH)
\t\t\t\t\t{
\t\t\t\t\t\ty = source.y + source.height + 2 * dx;
\t\t\t\t\t}
\t\t\t\t\telse if (dir == mxConstants.DIRECTION_EAST)
\t\t\t\t\t{
\t\t\t\t\t\tx = source.x - 2 * dy;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tx = source.x + source.width + 2 * dy;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (pt != null)
\t\t\t{
\t\t\t\tx = view.getRoutingCenterX(source);
\t\t\t\tdx = Math.max(Math.abs(x - pt.x), dy);
\t\t\t\ty = pt.y;
\t\t\t\tdy = 0;
\t\t\t}
\t\t\t
\t\t\tresult.push(new mxPoint(x - dx, y - dy));
\t\t\tresult.push(new mxPoint(x + dx, y + dy));
\t\t}
\t},
\t
\t/**
\t * Function: ElbowConnector
\t * 
\t * Uses either <SideToSide> or <TopToBottom> depending on the horizontal
\t * flag in the cell style. <SideToSide> is used if horizontal is true or
\t * unspecified. See <EntityRelation> for a description of the
\t * parameters.
\t */
\tElbowConnector: function(state, source, target, points, result)
\t{
\t\tvar pt = (points != null && points.length > 0) ? points[0] : null;

\t\tvar vertical = false;
\t\tvar horizontal = false;
\t\t
\t\tif (source != null && target != null)
\t\t{
\t\t\tif (pt != null)
\t\t\t{
\t\t\t\tvar left = Math.min(source.x, target.x);
\t\t\t\tvar right = Math.max(source.x + source.width,
\t\t\t\t\ttarget.x + target.width);
\t
\t\t\t\tvar top = Math.min(source.y, target.y);
\t\t\t\tvar bottom = Math.max(source.y + source.height,
\t\t\t\t\ttarget.y + target.height);

\t\t\t\tpt = state.view.transformControlPoint(state, pt);
\t\t\t\t\t
\t\t\t\tvertical = pt.y < top || pt.y > bottom;
\t\t\t\thorizontal = pt.x < left || pt.x > right;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar left = Math.max(source.x, target.x);
\t\t\t\tvar right = Math.min(source.x + source.width,
\t\t\t\t\ttarget.x + target.width);
\t\t\t\t\t
\t\t\t\tvertical = left == right;
\t\t\t\t
\t\t\t\tif (!vertical)
\t\t\t\t{
\t\t\t\t\tvar top = Math.max(source.y, target.y);
\t\t\t\t\tvar bottom = Math.min(source.y + source.height,
\t\t\t\t\t\ttarget.y + target.height);
\t\t\t\t\t\t
\t\t\t\t\thorizontal = top == bottom;
\t\t\t\t}
\t\t\t}
\t\t}

\t\tif (!horizontal && (vertical ||
\t\t\tstate.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL))
\t\t{
\t\t\tmxEdgeStyle.TopToBottom(state, source, target, points, result);
\t\t}
\t\telse
\t\t{
\t\t\tmxEdgeStyle.SideToSide(state, source, target, points, result);
\t\t}
\t},

\t/**
\t * Function: SideToSide
\t * 
\t * Implements a vertical elbow edge. See <EntityRelation> for a description
\t * of the parameters.
\t */
\tSideToSide: function(state, source, target, points, result)
\t{
\t\tvar view = state.view;
\t\tvar pt = (points != null && points.length > 0) ? points[0] : null;
\t\tvar pts = state.absolutePoints;
\t\tvar p0 = pts[0];
\t\tvar pe = pts[pts.length-1];
\t\t
\t\tif (pt != null)
\t\t{
\t\t\tpt = view.transformControlPoint(state, pt);
\t\t}
\t\t
\t\tif (p0 != null)
\t\t{
\t\t\tsource = new mxCellState();
\t\t\tsource.x = p0.x;
\t\t\tsource.y = p0.y;
\t\t}
\t\t
\t\tif (pe != null)
\t\t{
\t\t\ttarget = new mxCellState();
\t\t\ttarget.x = pe.x;
\t\t\ttarget.y = pe.y;
\t\t}
\t\t
\t\tif (source != null && target != null)
\t\t{
\t\t\tvar l = Math.max(source.x, target.x);
\t\t\tvar r = Math.min(source.x + source.width,
\t\t\t\t\t\t\t target.x + target.width);
\t
\t\t\tvar x = (pt != null) ? pt.x : Math.round(r + (l - r) / 2);
\t
\t\t\tvar y1 = view.getRoutingCenterY(source);
\t\t\tvar y2 = view.getRoutingCenterY(target);
\t
\t\t\tif (pt != null)
\t\t\t{
\t\t\t\tif (pt.y >= source.y && pt.y <= source.y + source.height)
\t\t\t\t{
\t\t\t\t\ty1 = pt.y;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (pt.y >= target.y && pt.y <= target.y + target.height)
\t\t\t\t{
\t\t\t\t\ty2 = pt.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (!mxUtils.contains(target, x, y1) &&
\t\t\t\t!mxUtils.contains(source, x, y1))
\t\t\t{
\t\t\t\tresult.push(new mxPoint(x,  y1));
\t\t\t}
\t
\t\t\tif (!mxUtils.contains(target, x, y2) &&
\t\t\t\t!mxUtils.contains(source, x, y2))
\t\t\t{
\t\t\t\tresult.push(new mxPoint(x, y2));
\t\t\t}
\t
\t\t\tif (result.length == 1)
\t\t\t{
\t\t\t\tif (pt != null)
\t\t\t\t{
\t\t\t\t\tif (!mxUtils.contains(target, x, pt.y) &&
\t\t\t\t\t\t!mxUtils.contains(source, x, pt.y))
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(new mxPoint(x, pt.y));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{\t
\t\t\t\t\tvar t = Math.max(source.y, target.y);
\t\t\t\t\tvar b = Math.min(source.y + source.height,
\t\t\t\t\t\t\t target.y + target.height);
\t\t\t\t\t\t 
\t\t\t\t\tresult.push(new mxPoint(x, t + (b - t) / 2));
\t\t\t\t}
\t\t\t}
\t\t}
\t},

\t/**
\t * Function: TopToBottom
\t * 
\t * Implements a horizontal elbow edge. See <EntityRelation> for a
\t * description of the parameters.
\t */
\tTopToBottom: function(state, source, target, points, result)
\t{
\t\tvar view = state.view;
\t\tvar pt = (points != null && points.length > 0) ? points[0] : null;
\t\tvar pts = state.absolutePoints;
\t\tvar p0 = pts[0];
\t\tvar pe = pts[pts.length-1];
\t\t
\t\tif (pt != null)
\t\t{
\t\t\tpt = view.transformControlPoint(state, pt);
\t\t}
\t\t
\t\tif (p0 != null)
\t\t{
\t\t\tsource = new mxCellState();
\t\t\tsource.x = p0.x;
\t\t\tsource.y = p0.y;
\t\t}
\t\t
\t\tif (pe != null)
\t\t{
\t\t\ttarget = new mxCellState();
\t\t\ttarget.x = pe.x;
\t\t\ttarget.y = pe.y;
\t\t}

\t\tif (source != null && target != null)
\t\t{
\t\t\tvar t = Math.max(source.y, target.y);
\t\t\tvar b = Math.min(source.y + source.height,
\t\t\t\t\t\t\t target.y + target.height);
\t
\t\t\tvar x = view.getRoutingCenterX(source);
\t\t\t
\t\t\tif (pt != null &&
\t\t\t\tpt.x >= source.x &&
\t\t\t\tpt.x <= source.x + source.width)
\t\t\t{
\t\t\t\tx = pt.x;
\t\t\t}
\t\t\t
\t\t\tvar y = (pt != null) ? pt.y : Math.round(b + (t - b) / 2);
\t\t\t
\t\t\tif (!mxUtils.contains(target, x, y) &&
\t\t\t\t!mxUtils.contains(source, x, y))
\t\t\t{
\t\t\t\tresult.push(new mxPoint(x, y));\t\t\t\t\t\t
\t\t\t}
\t\t\t
\t\t\tif (pt != null &&
\t\t\t\tpt.x >= target.x &&
\t\t\t\tpt.x <= target.x + target.width)
\t\t\t{
\t\t\t\tx = pt.x;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tx = view.getRoutingCenterX(target);
\t\t\t}
\t\t\t
\t\t\tif (!mxUtils.contains(target, x, y) &&
\t\t\t\t!mxUtils.contains(source, x, y))
\t\t\t{
\t\t\t\tresult.push(new mxPoint(x, y));\t\t\t\t\t\t
\t\t\t}
\t\t\t
\t\t\tif (result.length == 1)
\t\t\t{
\t\t\t\tif (pt != null && result.length == 1)
\t\t\t\t{
\t\t\t\t\tif (!mxUtils.contains(target, pt.x, y) &&
\t\t\t\t\t\t!mxUtils.contains(source, pt.x, y))
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(new mxPoint(pt.x, y));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar l = Math.max(source.x, target.x);
\t\t\t\t\tvar r = Math.min(source.x + source.width,
\t\t\t\t\t\t\t target.x + target.width);
\t\t\t\t\t\t 
\t\t\t\t\tresult.push(new mxPoint(l + (r - l) / 2, y));
\t\t\t\t}
\t\t\t}
\t\t}
\t},

\t/**
\t * Function: SegmentConnector
\t * 
\t * Implements an orthogonal edge style. Use <mxEdgeSegmentHandler>
\t * as an interactive handler for this style.
\t * 
\t * state - <mxCellState> that represents the edge to be updated.
\t * sourceScaled - <mxCellState> that represents the source terminal.
\t * targetScaled - <mxCellState> that represents the target terminal.
\t * controlHints - List of relative control points.
\t * result - Array of <mxPoints> that represent the actual points of the
\t * edge.
\t *
\t */
\tSegmentConnector: function(state, sourceScaled, targetScaled, controlHints, result)
\t{
\t\t// Creates array of all way- and terminalpoints
\t\tvar pts = mxEdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
\t\tvar source = mxEdgeStyle.scaleCellState(sourceScaled, state.view.scale);
\t\tvar target = mxEdgeStyle.scaleCellState(targetScaled, state.view.scale);
\t\tvar tol = 1;
\t\t
\t\t// Whether the first segment outgoing from the source end is horizontal
\t\tvar lastPushed = (result.length > 0) ? result[0] : null;
\t\tvar horizontal = true;
\t\tvar hint = null;
\t\t
\t\t// Adds waypoints only if outside of tolerance
\t\tfunction pushPoint(pt)
\t\t{
\t\t\tpt.x = Math.round(pt.x * state.view.scale * 10) / 10;
\t\t\tpt.y = Math.round(pt.y * state.view.scale * 10) / 10;

\t\t\tif (lastPushed == null || Math.abs(lastPushed.x - pt.x) >= tol || Math.abs(lastPushed.y - pt.y) >= Math.max(1, state.view.scale))
\t\t\t{
\t\t\t\tresult.push(pt);
\t\t\t\tlastPushed = pt;
\t\t\t}
\t\t\t
\t\t\treturn lastPushed;
\t\t};

\t\t// Adds the first point
\t\tvar pt = pts[0];
\t\t
\t\tif (pt == null && source != null)
\t\t{
\t\t\tpt = new mxPoint(state.view.getRoutingCenterX(source), state.view.getRoutingCenterY(source));
\t\t}
\t\telse if (pt != null)
\t\t{
\t\t\tpt = pt.clone();
\t\t}
\t\t
\t\tvar lastInx = pts.length - 1;

\t\t// Adds the waypoints
\t\tif (controlHints != null && controlHints.length > 0)
\t\t{
\t\t\t// Converts all hints and removes nulls
\t\t\tvar hints = [];
\t\t\t
\t\t\tfor (var i = 0; i < controlHints.length; i++)
\t\t\t{
\t\t\t\tvar tmp = state.view.transformControlPoint(state, controlHints[i], true);
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\thints.push(tmp);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (hints.length == 0)
\t\t\t{
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\t// Aligns source and target hint to fixed points
\t\t\tif (pt != null && hints[0] != null)
\t\t\t{
\t\t\t\tif (Math.abs(hints[0].x - pt.x) < tol)
\t\t\t\t{
\t\t\t\t\thints[0].x = pt.x;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (Math.abs(hints[0].y - pt.y) < tol)
\t\t\t\t{
\t\t\t\t\thints[0].y = pt.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar pe = pts[lastInx];
\t\t\t
\t\t\tif (pe != null && hints[hints.length - 1] != null)
\t\t\t{
\t\t\t\tif (Math.abs(hints[hints.length - 1].x - pe.x) < tol)
\t\t\t\t{
\t\t\t\t\thints[hints.length - 1].x = pe.x;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (Math.abs(hints[hints.length - 1].y - pe.y) < tol)
\t\t\t\t{
\t\t\t\t\thints[hints.length - 1].y = pe.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\thint = hints[0];

\t\t\tvar currentTerm = source;
\t\t\tvar currentPt = pts[0];
\t\t\tvar hozChan = false;
\t\t\tvar vertChan = false;
\t\t\tvar currentHint = hint;
\t\t\t
\t\t\tif (currentPt != null)
\t\t\t{
\t\t\t\tcurrentTerm = null;
\t\t\t}
\t\t\t
\t\t\t// Check for alignment with fixed points and with channels
\t\t\t// at source and target segments only
\t\t\tfor (var i = 0; i < 2; i++)
\t\t\t{
\t\t\t\tvar fixedVertAlign = currentPt != null && currentPt.x == currentHint.x;
\t\t\t\tvar fixedHozAlign = currentPt != null && currentPt.y == currentHint.y;
\t\t\t\t
\t\t\t\tvar inHozChan = currentTerm != null && (currentHint.y >= currentTerm.y &&
\t\t\t\t\t\tcurrentHint.y <= currentTerm.y + currentTerm.height);
\t\t\t\tvar inVertChan = currentTerm != null && (currentHint.x >= currentTerm.x &&
\t\t\t\t\t\tcurrentHint.x <= currentTerm.x + currentTerm.width);

\t\t\t\thozChan = fixedHozAlign || (currentPt == null && inHozChan);
\t\t\t\tvertChan = fixedVertAlign || (currentPt == null && inVertChan);
\t\t\t\t
\t\t\t\t// If the current hint falls in both the hor and vert channels in the case
\t\t\t\t// of a floating port, or if the hint is exactly co-incident with a 
\t\t\t\t// fixed point, ignore the source and try to work out the orientation
\t\t\t\t// from the target end
\t\t\t\tif (i==0 && ((hozChan && vertChan) || (fixedVertAlign && fixedHozAlign)))
\t\t\t\t{
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tif (currentPt != null && (!fixedHozAlign && !fixedVertAlign) && (inHozChan || inVertChan)) 
\t\t\t\t\t{
\t\t\t\t\t\thorizontal = inHozChan ? false : true;
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t
\t\t\t\t\tif (vertChan || hozChan)
\t\t\t\t\t{
\t\t\t\t\t\thorizontal = hozChan;
\t\t\t\t\t\t
\t\t\t\t\t\tif (i == 1)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t// Work back from target end
\t\t\t\t\t\t\thorizontal = hints.length % 2 == 0 ? hozChan : vertChan;
\t\t\t\t\t\t}
\t
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tcurrentTerm = target;
\t\t\t\tcurrentPt = pts[lastInx];
\t\t\t\t
\t\t\t\tif (currentPt != null)
\t\t\t\t{
\t\t\t\t\tcurrentTerm = null;
\t\t\t\t}
\t\t\t\t
\t\t\t\tcurrentHint = hints[hints.length - 1];
\t\t\t\t
\t\t\t\tif (fixedVertAlign && fixedHozAlign)
\t\t\t\t{
\t\t\t\t\thints = hints.slice(1);
\t\t\t\t}
\t\t\t}

\t\t\tif (horizontal && ((pts[0] != null && pts[0].y != hint.y) ||
\t\t\t\t(pts[0] == null && source != null &&
\t\t\t\t(hint.y < source.y || hint.y > source.y + source.height))))
\t\t\t{
\t\t\t\tpushPoint(new mxPoint(pt.x, hint.y));
\t\t\t}
\t\t\telse if (!horizontal && ((pts[0] != null && pts[0].x != hint.x) ||
\t\t\t\t\t(pts[0] == null && source != null &&
\t\t\t\t\t(hint.x < source.x || hint.x > source.x + source.width))))
\t\t\t{
\t\t\t\tpushPoint(new mxPoint(hint.x, pt.y));
\t\t\t}
\t\t\t
\t\t\tif (horizontal)
\t\t\t{
\t\t\t\tpt.y = hint.y;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tpt.x = hint.x;
\t\t\t}
\t\t
\t\t\tfor (var i = 0; i < hints.length; i++)
\t\t\t{
\t\t\t\thorizontal = !horizontal;
\t\t\t\thint = hints[i];
\t\t\t\t
//\t\t\t\tmxLog.show();
//\t\t\t\tmxLog.debug('hint', i, hint.x, hint.y);
\t\t\t\t
\t\t\t\tif (horizontal)
\t\t\t\t{
\t\t\t\t\tpt.y = hint.y;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tpt.x = hint.x;
\t\t\t\t}
\t\t
\t\t\t\tpushPoint(pt.clone());
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\thint = pt;
\t\t\t// FIXME: First click in connect preview toggles orientation
\t\t\thorizontal = true;
\t\t}

\t\t// Adds the last point
\t\tpt = pts[lastInx];

\t\tif (pt == null && target != null)
\t\t{
\t\t\tpt = new mxPoint(state.view.getRoutingCenterX(target), state.view.getRoutingCenterY(target));
\t\t}
\t\t
\t\tif (pt != null)
\t\t{
\t\t\tif (hint != null)
\t\t\t{
\t\t\t\tif (horizontal && ((pts[lastInx] != null && pts[lastInx].y != hint.y) ||
\t\t\t\t\t(pts[lastInx] == null && target != null &&
\t\t\t\t\t(hint.y < target.y || hint.y > target.y + target.height))))
\t\t\t\t{
\t\t\t\t\tpushPoint(new mxPoint(pt.x, hint.y));
\t\t\t\t}
\t\t\t\telse if (!horizontal && ((pts[lastInx] != null && pts[lastInx].x != hint.x) ||
\t\t\t\t\t\t(pts[lastInx] == null && target != null &&
\t\t\t\t\t\t(hint.x < target.x || hint.x > target.x + target.width))))
\t\t\t\t{
\t\t\t\t\tpushPoint(new mxPoint(hint.x, pt.y));
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\t// Removes bends inside the source terminal for floating ports
\t\tif (pts[0] == null && source != null)
\t\t{
\t\t\twhile (result.length > 1 && result[1] != null &&
\t\t\t\tmxUtils.contains(source, result[1].x, result[1].y))
\t\t\t{
\t\t\t\tresult.splice(1, 1);
\t\t\t}
\t\t}
\t\t
\t\t// Removes bends inside the target terminal
\t\tif (pts[lastInx] == null && target != null)
\t\t{
\t\t\twhile (result.length > 1 && result[result.length - 1] != null &&
\t\t\t\tmxUtils.contains(target, result[result.length - 1].x, result[result.length - 1].y))
\t\t\t{
\t\t\t\tresult.splice(result.length - 1, 1);
\t\t\t}
\t\t}
\t\t
\t\t// Removes last point if inside tolerance with end point
\t\tif (pe != null && result[result.length - 1] != null &&
\t\t\tMath.abs(pe.x - result[result.length - 1].x) <= tol &&
\t\t\tMath.abs(pe.y - result[result.length - 1].y) <= tol)
\t\t{
\t\t\tresult.splice(result.length - 1, 1);
\t\t\t
\t\t\t// Lines up second last point in result with end point
\t\t\tif (result[result.length - 1] != null)
\t\t\t{
\t\t\t\tif (Math.abs(result[result.length - 1].x - pe.x) < tol)
\t\t\t\t{
\t\t\t\t\tresult[result.length - 1].x = pe.x;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (Math.abs(result[result.length - 1].y - pe.y) < tol)
\t\t\t\t{
\t\t\t\t\tresult[result.length - 1].y = pe.y;
\t\t\t\t}
\t\t\t}
\t\t}
\t},
\t
\torthBuffer: 10,
\t
\torthPointsFallback: true,

\tdirVectors: [ [ -1, 0 ],
\t\t\t[ 0, -1 ], [ 1, 0 ], [ 0, 1 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ] ],

\twayPoints1: [ [ 0, 0], [ 0, 0],  [ 0, 0], [ 0, 0], [ 0, 0],  [ 0, 0],
\t              [ 0, 0],  [ 0, 0], [ 0, 0],  [ 0, 0], [ 0, 0],  [ 0, 0] ],

\troutePatterns: [
\t\t[ [ 513, 2308, 2081, 2562 ], [ 513, 1090, 514, 2184, 2114, 2561 ],
\t\t\t[ 513, 1090, 514, 2564, 2184, 2562 ],
\t\t\t[ 513, 2308, 2561, 1090, 514, 2568, 2308 ] ],
\t[ [ 514, 1057, 513, 2308, 2081, 2562 ], [ 514, 2184, 2114, 2561 ],
\t\t\t[ 514, 2184, 2562, 1057, 513, 2564, 2184 ],
\t\t\t[ 514, 1057, 513, 2568, 2308, 2561 ] ],
\t[ [ 1090, 514, 1057, 513, 2308, 2081, 2562 ], [ 2114, 2561 ],
\t\t\t[ 1090, 2562, 1057, 513, 2564, 2184 ],
\t\t\t[ 1090, 514, 1057, 513, 2308, 2561, 2568 ] ],
\t[ [ 2081, 2562 ], [ 1057, 513, 1090, 514, 2184, 2114, 2561 ],
\t\t\t[ 1057, 513, 1090, 514, 2184, 2562, 2564 ],
\t\t\t[ 1057, 2561, 1090, 514, 2568, 2308 ] ] ],
\t
\tinlineRoutePatterns: [
\t\t\t[ null, [ 2114, 2568 ], null, null ],
\t\t\t[ null, [ 514, 2081, 2114, 2568 ] , null, null ],
\t\t\t[ null, [ 2114, 2561 ], null, null ],
\t\t\t[ [ 2081, 2562 ], [ 1057, 2114, 2568 ],
\t\t\t\t\t[ 2184, 2562 ],
\t\t\t\t\tnull ] ],
\tvertexSeperations: [],

\tlimits: [
\t       [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
\t       [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ],

\tLEFT_MASK: 32,

\tTOP_MASK: 64,

\tRIGHT_MASK: 128,

\tBOTTOM_MASK: 256,

\tLEFT: 1,

\tTOP: 2,

\tRIGHT: 4,

\tBOTTOM: 8,

\t// TODO remove magic numbers
\tSIDE_MASK: 480,
\t//mxEdgeStyle.LEFT_MASK | mxEdgeStyle.TOP_MASK | mxEdgeStyle.RIGHT_MASK
\t//| mxEdgeStyle.BOTTOM_MASK,

\tCENTER_MASK: 512,

\tSOURCE_MASK: 1024,

\tTARGET_MASK: 2048,

\tVERTEX_MASK: 3072,
\t// mxEdgeStyle.SOURCE_MASK | mxEdgeStyle.TARGET_MASK,
\t
\tgetJettySize: function(state, isSource)
\t{
\t\tvar value = mxUtils.getValue(state.style, (isSource) ? mxConstants.STYLE_SOURCE_JETTY_SIZE :
\t\t\tmxConstants.STYLE_TARGET_JETTY_SIZE, mxUtils.getValue(state.style,
\t\t\t\t\tmxConstants.STYLE_JETTY_SIZE, mxEdgeStyle.orthBuffer));
\t\t
\t\tif (value == 'auto')
\t\t{
\t\t\t// Computes the automatic jetty size
\t\t\tvar type = mxUtils.getValue(state.style, (isSource) ? mxConstants.STYLE_STARTARROW : mxConstants.STYLE_ENDARROW, mxConstants.NONE);
\t\t\t
\t\t\tif (type != mxConstants.NONE)
\t\t\t{
\t\t\t\tvar size = mxUtils.getNumber(state.style, (isSource) ? mxConstants.STYLE_STARTSIZE : mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE);
\t\t\t\tvalue = Math.max(2, Math.ceil((size + mxEdgeStyle.orthBuffer) / mxEdgeStyle.orthBuffer)) * mxEdgeStyle.orthBuffer;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvalue = 2 * mxEdgeStyle.orthBuffer;
\t\t\t}
\t\t}
\t\t
\t\treturn value;
\t},
\t
\t/**
\t * Function: scalePointArray
\t * 
\t * Scales an array of <mxPoint>
\t * 
\t * Parameters:
\t * 
\t * points - array of <mxPoint> to scale
\t * scale - the scaling to divide by
\t * 
\t */
\tscalePointArray: function(points, scale)
\t{
\t\tvar result = [];

\t\tif (points != null)
\t\t{
\t\t\tfor (var i = 0; i < points.length; i++)
\t\t\t{
\t\t\t\tif (points[i] != null)
\t\t\t\t{
\t\t\t\t\tvar pt = new mxPoint(Math.round(points[i].x / scale * 10) / 10,
\t\t\t\t\t\t\t\t\t\tMath.round(points[i].y / scale * 10) / 10);
\t\t\t\t\tresult[i] = pt;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tresult[i] = null;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tresult = null;
\t\t}
\t\t
\t\treturn result;
\t},
\t
\t/**
\t * Function: scaleCellState
\t * 
\t * Scales an <mxCellState>
\t * 
\t * Parameters:
\t * 
\t * state - <mxCellState> to scale
\t * scale - the scaling to divide by
\t * 
\t */
\tscaleCellState: function(state, scale)
\t{
\t\tvar result = null;

\t\tif (state != null)
\t\t{
\t\t\tresult = state.clone();
\t\t\tresult.setRect(Math.round(state.x / scale * 10) / 10,
\t\t\t\t\t\t\tMath.round(state.y / scale * 10) / 10,
\t\t\t\t\t\t\tMath.round(state.width / scale * 10) / 10,
\t\t\t\t\t\t\tMath.round(state.height / scale * 10) / 10);
\t\t}
\t\telse
\t\t{
\t\t\tresult = null;
\t\t}
\t\t
\t\treturn result;
\t},

\t/**
\t * Function: OrthConnector
\t * 
\t * Implements a local orthogonal router between the given
\t * cells.
\t * 
\t * Parameters:
\t * 
\t * state - <mxCellState> that represents the edge to be updated.
\t * sourceScaled - <mxCellState> that represents the source terminal.
\t * targetScaled - <mxCellState> that represents the target terminal.
\t * controlHints - List of relative control points.
\t * result - Array of <mxPoints> that represent the actual points of the
\t * edge.
\t * 
\t */
\tOrthConnector: function(state, sourceScaled, targetScaled, controlHints, result)
\t{
\t\tvar graph = state.view.graph;
\t\tvar sourceEdge = source == null ? false : graph.getModel().isEdge(source.cell);
\t\tvar targetEdge = target == null ? false : graph.getModel().isEdge(target.cell);

\t\tvar pts = mxEdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
\t\tvar source = mxEdgeStyle.scaleCellState(sourceScaled, state.view.scale);
\t\tvar target = mxEdgeStyle.scaleCellState(targetScaled, state.view.scale);

\t\tvar p0 = pts[0];
\t\tvar pe = pts[pts.length-1];
\t\t
\t\tvar sourceX = source != null ? source.x : p0.x;
\t\tvar sourceY = source != null ? source.y : p0.y;
\t\tvar sourceWidth = source != null ? source.width : 0;
\t\tvar sourceHeight = source != null ? source.height : 0;
\t\t
\t\tvar targetX = target != null ? target.x : pe.x;
\t\tvar targetY = target != null ? target.y : pe.y;
\t\tvar targetWidth = target != null ? target.width : 0;
\t\tvar targetHeight = target != null ? target.height : 0;

\t\tvar sourceBuffer = mxEdgeStyle.getJettySize(state, true);
\t\tvar targetBuffer = mxEdgeStyle.getJettySize(state, false);
\t\t
\t\t//console.log('sourceBuffer', sourceBuffer);
\t\t//console.log('targetBuffer', targetBuffer);
\t\t// Workaround for loop routing within buffer zone
\t\tif (source != null && target == source)
\t\t{
\t\t\ttargetBuffer = Math.max(sourceBuffer, targetBuffer);
\t\t\tsourceBuffer = targetBuffer;
\t\t}
\t\t
\t\tvar totalBuffer = targetBuffer + sourceBuffer;
\t\t// console.log('totalBuffer', totalBuffer);
\t\tvar tooShort = false;
\t\t
\t\t// Checks minimum distance for fixed points and falls back to segment connector
\t\tif (p0 != null && pe != null)
\t\t{
\t\t\tvar dx = pe.x - p0.x;
\t\t\tvar dy = pe.y - p0.y;
\t\t\t
\t\t\ttooShort = dx * dx + dy * dy < totalBuffer * totalBuffer;
\t\t}

\t\tif (tooShort || (mxEdgeStyle.orthPointsFallback && (controlHints != null &&
\t\t\t\tcontrolHints.length > 0)) || sourceEdge || targetEdge)
\t\t{
\t\t\tmxEdgeStyle.SegmentConnector(state, sourceScaled, targetScaled, controlHints, result);
\t\t\t
\t\t\treturn;
\t\t}

\t\t// Determine the side(s) of the source and target vertices
\t\t// that the edge may connect to
\t\t// portConstraint [source, target]
\t\tvar portConstraint = [mxConstants.DIRECTION_MASK_ALL, mxConstants.DIRECTION_MASK_ALL];
\t\tvar rotation = 0;
\t\t
\t\tif (source != null)
\t\t{
\t\t\tportConstraint[0] = mxUtils.getPortConstraints(source, state, true, 
\t\t\t\t\tmxConstants.DIRECTION_MASK_ALL);
\t\t\trotation = mxUtils.getValue(source.style, mxConstants.STYLE_ROTATION, 0);
\t\t\t
\t\t\t//console.log('source rotation', rotation);
\t\t\t
\t\t\tif (rotation != 0)
\t\t\t{
\t\t\t\tvar newRect = mxUtils.getBoundingBox(new mxRectangle(sourceX, sourceY, sourceWidth, sourceHeight), rotation);
\t\t\t\tsourceX = newRect.x; 
\t\t\t\tsourceY = newRect.y;
\t\t\t\tsourceWidth = newRect.width;
\t\t\t\tsourceHeight = newRect.height;
\t\t\t}
\t\t}

\t\tif (target != null)
\t\t{
\t\t\tportConstraint[1] = mxUtils.getPortConstraints(target, state, false,
\t\t\t\tmxConstants.DIRECTION_MASK_ALL);
\t\t\trotation = mxUtils.getValue(target.style, mxConstants.STYLE_ROTATION, 0);
\t\t\t
\t\t\t//console.log('target rotation', rotation);

\t\t\tif (rotation != 0)
\t\t\t{
\t\t\t\tvar newRect = mxUtils.getBoundingBox(new mxRectangle(targetX, targetY, targetWidth, targetHeight), rotation);
\t\t\t\ttargetX = newRect.x;
\t\t\t\ttargetY = newRect.y;
\t\t\t\ttargetWidth = newRect.width;
\t\t\t\ttargetHeight = newRect.height;
\t\t\t}
\t\t}

\t\t//console.log('source' , sourceX, sourceY, sourceWidth, sourceHeight);
\t\t//console.log('targetX' , targetX, targetY, targetWidth, targetHeight);

\t\tvar dir = [0, 0];

\t\t// Work out which faces of the vertices present against each other
\t\t// in a way that would allow a 3-segment connection if port constraints
\t\t// permitted.
\t\t// geo -> [source, target] [x, y, width, height]
\t\tvar geo = [ [sourceX, sourceY, sourceWidth, sourceHeight] ,
\t\t            [targetX, targetY, targetWidth, targetHeight] ];
\t\tvar buffer = [sourceBuffer, targetBuffer];

\t\tfor (var i = 0; i < 2; i++)
\t\t{
\t\t\tmxEdgeStyle.limits[i][1] = geo[i][0] - buffer[i];
\t\t\tmxEdgeStyle.limits[i][2] = geo[i][1] - buffer[i];
\t\t\tmxEdgeStyle.limits[i][4] = geo[i][0] + geo[i][2] + buffer[i];
\t\t\tmxEdgeStyle.limits[i][8] = geo[i][1] + geo[i][3] + buffer[i];
\t\t}
\t\t
\t\t// Work out which quad the target is in
\t\tvar sourceCenX = geo[0][0] + geo[0][2] / 2.0;
\t\tvar sourceCenY = geo[0][1] + geo[0][3] / 2.0;
\t\tvar targetCenX = geo[1][0] + geo[1][2] / 2.0;
\t\tvar targetCenY = geo[1][1] + geo[1][3] / 2.0;
\t\t
\t\tvar dx = sourceCenX - targetCenX;
\t\tvar dy = sourceCenY - targetCenY;

\t\tvar quad = 0;

\t\t// 0 | 1
\t\t// -----
\t\t// 3 | 2
\t\t
\t\tif (dx < 0)
\t\t{
\t\t\tif (dy < 0)
\t\t\t{
\t\t\t\tquad = 2;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tquad = 1;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (dy <= 0)
\t\t\t{
\t\t\t\tquad = 3;
\t\t\t\t
\t\t\t\t// Special case on x = 0 and negative y
\t\t\t\tif (dx == 0)
\t\t\t\t{
\t\t\t\t\tquad = 2;
\t\t\t\t}
\t\t\t}
\t\t}

\t\t//console.log('quad', quad);

\t\t// Check for connection constraints
\t\tvar currentTerm = null;
\t\t
\t\tif (source != null)
\t\t{
\t\t\tcurrentTerm = p0;
\t\t}

\t\tvar constraint = [ [0.5, 0.5] , [0.5, 0.5] ];

\t\tfor (var i = 0; i < 2; i++)
\t\t{
\t\t\tif (currentTerm != null)
\t\t\t{
\t\t\t\tconstraint[i][0] = (currentTerm.x - geo[i][0]) / geo[i][2];
\t\t\t\t
\t\t\t\tif (Math.abs(currentTerm.x - geo[i][0]) <= 1)
\t\t\t\t{
\t\t\t\t\tdir[i] = mxConstants.DIRECTION_MASK_WEST;
\t\t\t\t}
\t\t\t\telse if (Math.abs(currentTerm.x - geo[i][0] - geo[i][2]) <= 1)
\t\t\t\t{
\t\t\t\t\tdir[i] = mxConstants.DIRECTION_MASK_EAST;
\t\t\t\t}

\t\t\t\tconstraint[i][1] = (currentTerm.y - geo[i][1]) / geo[i][3];

\t\t\t\tif (Math.abs(currentTerm.y - geo[i][1]) <= 1)
\t\t\t\t{
\t\t\t\t\tdir[i] = mxConstants.DIRECTION_MASK_NORTH;
\t\t\t\t}
\t\t\t\telse if (Math.abs(currentTerm.y - geo[i][1] - geo[i][3]) <= 1)
\t\t\t\t{
\t\t\t\t\tdir[i] = mxConstants.DIRECTION_MASK_SOUTH;
\t\t\t\t}
\t\t\t}

\t\t\tcurrentTerm = null;
\t\t\t
\t\t\tif (target != null)
\t\t\t{
\t\t\t\tcurrentTerm = pe;
\t\t\t}
\t\t}

\t\tvar sourceTopDist = geo[0][1] - (geo[1][1] + geo[1][3]);
\t\tvar sourceLeftDist = geo[0][0] - (geo[1][0] + geo[1][2]);
\t\tvar sourceBottomDist = geo[1][1] - (geo[0][1] + geo[0][3]);
\t\tvar sourceRightDist = geo[1][0] - (geo[0][0] + geo[0][2]);

\t\tmxEdgeStyle.vertexSeperations[1] = Math.max(sourceLeftDist - totalBuffer, 0);
\t\tmxEdgeStyle.vertexSeperations[2] = Math.max(sourceTopDist - totalBuffer, 0);
\t\tmxEdgeStyle.vertexSeperations[4] = Math.max(sourceBottomDist - totalBuffer, 0);
\t\tmxEdgeStyle.vertexSeperations[3] = Math.max(sourceRightDist - totalBuffer, 0);
\t\t\t\t
\t\t//==============================================================
\t\t// Start of source and target direction determination

\t\t// Work through the preferred orientations by relative positioning
\t\t// of the vertices and list them in preferred and available order
\t\t
\t\tvar dirPref = [];
\t\tvar horPref = [];
\t\tvar vertPref = [];

\t\thorPref[0] = (sourceLeftDist >= sourceRightDist) ? mxConstants.DIRECTION_MASK_WEST
\t\t\t\t: mxConstants.DIRECTION_MASK_EAST;
\t\tvertPref[0] = (sourceTopDist >= sourceBottomDist) ? mxConstants.DIRECTION_MASK_NORTH
\t\t\t\t: mxConstants.DIRECTION_MASK_SOUTH;

\t\thorPref[1] = mxUtils.reversePortConstraints(horPref[0]);
\t\tvertPref[1] = mxUtils.reversePortConstraints(vertPref[0]);
\t\t
\t\tvar preferredHorizDist = sourceLeftDist >= sourceRightDist ? sourceLeftDist
\t\t\t\t: sourceRightDist;
\t\tvar preferredVertDist = sourceTopDist >= sourceBottomDist ? sourceTopDist
\t\t\t\t: sourceBottomDist;

\t\tvar prefOrdering = [ [0, 0] , [0, 0] ];
\t\tvar preferredOrderSet = false;

\t\t// If the preferred port isn't available, switch it
\t\tfor (var i = 0; i < 2; i++)
\t\t{
\t\t\tif (dir[i] != 0x0)
\t\t\t{
\t\t\t\tcontinue;
\t\t\t}

\t\t\tif ((horPref[i] & portConstraint[i]) == 0)
\t\t\t{
\t\t\t\thorPref[i] = mxUtils.reversePortConstraints(horPref[i]);
\t\t\t}

\t\t\tif ((vertPref[i] & portConstraint[i]) == 0)
\t\t\t{
\t\t\t\tvertPref[i] = mxUtils
\t\t\t\t\t\t.reversePortConstraints(vertPref[i]);
\t\t\t}

\t\t\tprefOrdering[i][0] = vertPref[i];
\t\t\tprefOrdering[i][1] = horPref[i];
\t\t}

\t\tif (preferredVertDist > 0
\t\t\t\t&& preferredHorizDist > 0)
\t\t{
\t\t\t// Possibility of two segment edge connection
\t\t\tif (((horPref[0] & portConstraint[0]) > 0)
\t\t\t\t\t&& ((vertPref[1] & portConstraint[1]) > 0))
\t\t\t{
\t\t\t\tprefOrdering[0][0] = horPref[0];
\t\t\t\tprefOrdering[0][1] = vertPref[0];
\t\t\t\tprefOrdering[1][0] = vertPref[1];
\t\t\t\tprefOrdering[1][1] = horPref[1];
\t\t\t\tpreferredOrderSet = true;
\t\t\t}
\t\t\telse if (((vertPref[0] & portConstraint[0]) > 0)
\t\t\t\t\t&& ((horPref[1] & portConstraint[1]) > 0))
\t\t\t{
\t\t\t\tprefOrdering[0][0] = vertPref[0];
\t\t\t\tprefOrdering[0][1] = horPref[0];
\t\t\t\tprefOrdering[1][0] = horPref[1];
\t\t\t\tprefOrdering[1][1] = vertPref[1];
\t\t\t\tpreferredOrderSet = true;
\t\t\t}
\t\t}
\t\t
\t\tif (preferredVertDist > 0 && !preferredOrderSet)
\t\t{
\t\t\tprefOrdering[0][0] = vertPref[0];
\t\t\tprefOrdering[0][1] = horPref[0];
\t\t\tprefOrdering[1][0] = vertPref[1];
\t\t\tprefOrdering[1][1] = horPref[1];
\t\t\tpreferredOrderSet = true;

\t\t}
\t\t
\t\tif (preferredHorizDist > 0 && !preferredOrderSet)
\t\t{
\t\t\tprefOrdering[0][0] = horPref[0];
\t\t\tprefOrdering[0][1] = vertPref[0];
\t\t\tprefOrdering[1][0] = horPref[1];
\t\t\tprefOrdering[1][1] = vertPref[1];
\t\t\tpreferredOrderSet = true;
\t\t}

\t\t// The source and target prefs are now an ordered list of
\t\t// the preferred port selections
\t\t// If the list contains gaps, compact it

\t\tfor (var i = 0; i < 2; i++)
\t\t{
\t\t\tif (dir[i] != 0x0)
\t\t\t{
\t\t\t\tcontinue;
\t\t\t}

\t\t\tif ((prefOrdering[i][0] & portConstraint[i]) == 0)
\t\t\t{
\t\t\t\tprefOrdering[i][0] = prefOrdering[i][1];
\t\t\t}

\t\t\tdirPref[i] = prefOrdering[i][0] & portConstraint[i];
\t\t\tdirPref[i] |= (prefOrdering[i][1] & portConstraint[i]) << 8;
\t\t\tdirPref[i] |= (prefOrdering[1 - i][i] & portConstraint[i]) << 16;
\t\t\tdirPref[i] |= (prefOrdering[1 - i][1 - i] & portConstraint[i]) << 24;

\t\t\tif ((dirPref[i] & 0xF) == 0)
\t\t\t{
\t\t\t\tdirPref[i] = dirPref[i] << 8;
\t\t\t}
\t\t\t
\t\t\tif ((dirPref[i] & 0xF00) == 0)
\t\t\t{
\t\t\t\tdirPref[i] = (dirPref[i] & 0xF) | dirPref[i] >> 8;
\t\t\t}
\t\t\t
\t\t\tif ((dirPref[i] & 0xF0000) == 0)
\t\t\t{
\t\t\t\tdirPref[i] = (dirPref[i] & 0xFFFF)
\t\t\t\t\t\t| ((dirPref[i] & 0xF000000) >> 8);
\t\t\t}

\t\t\tdir[i] = dirPref[i] & 0xF;

\t\t\tif (portConstraint[i] == mxConstants.DIRECTION_MASK_WEST
\t\t\t\t\t|| portConstraint[i] == mxConstants.DIRECTION_MASK_NORTH
\t\t\t\t\t|| portConstraint[i] == mxConstants.DIRECTION_MASK_EAST
\t\t\t\t\t|| portConstraint[i] == mxConstants.DIRECTION_MASK_SOUTH)
\t\t\t{
\t\t\t\tdir[i] = portConstraint[i];
\t\t\t}
\t\t}

\t\t//==============================================================
\t\t// End of source and target direction determination

\t\tvar sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3
\t\t\t\t: dir[0];
\t\tvar targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3
\t\t\t\t: dir[1];

\t\tsourceIndex -= quad;
\t\ttargetIndex -= quad;

\t\tif (sourceIndex < 1)
\t\t{
\t\t\tsourceIndex += 4;
\t\t}
\t\t
\t\tif (targetIndex < 1)
\t\t{
\t\t\ttargetIndex += 4;
\t\t}

\t\tvar routePattern = mxEdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1];
\t\t
\t\t//console.log('routePattern', routePattern);

\t\tmxEdgeStyle.wayPoints1[0][0] = geo[0][0];
\t\tmxEdgeStyle.wayPoints1[0][1] = geo[0][1];

\t\tswitch (dir[0])
\t\t{
\t\t\tcase mxConstants.DIRECTION_MASK_WEST:
\t\t\t\tmxEdgeStyle.wayPoints1[0][0] -= sourceBuffer;
\t\t\t\tmxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3];
\t\t\t\tbreak;
\t\t\tcase mxConstants.DIRECTION_MASK_SOUTH:
\t\t\t\tmxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2];
\t\t\t\tmxEdgeStyle.wayPoints1[0][1] += geo[0][3] + sourceBuffer;
\t\t\t\tbreak;
\t\t\tcase mxConstants.DIRECTION_MASK_EAST:
\t\t\t\tmxEdgeStyle.wayPoints1[0][0] += geo[0][2] + sourceBuffer;
\t\t\t\tmxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3];
\t\t\t\tbreak;
\t\t\tcase mxConstants.DIRECTION_MASK_NORTH:
\t\t\t\tmxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2];
\t\t\t\tmxEdgeStyle.wayPoints1[0][1] -= sourceBuffer;
\t\t\t\tbreak;
\t\t}

\t\tvar currentIndex = 0;

\t\t// Orientation, 0 horizontal, 1 vertical
\t\tvar lastOrientation = (dir[0] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0
\t\t\t\t: 1;
\t\tvar initialOrientation = lastOrientation;
\t\tvar currentOrientation = 0;

\t\tfor (var i = 0; i < routePattern.length; i++)
\t\t{
\t\t\tvar nextDirection = routePattern[i] & 0xF;

\t\t\t// Rotate the index of this direction by the quad
\t\t\t// to get the real direction
\t\t\tvar directionIndex = nextDirection == mxConstants.DIRECTION_MASK_EAST ? 3
\t\t\t\t\t: nextDirection;

\t\t\tdirectionIndex += quad;

\t\t\tif (directionIndex > 4)
\t\t\t{
\t\t\t\tdirectionIndex -= 4;
\t\t\t}

\t\t\tvar direction = mxEdgeStyle.dirVectors[directionIndex - 1];

\t\t\tcurrentOrientation = (directionIndex % 2 > 0) ? 0 : 1;
\t\t\t// Only update the current index if the point moved
\t\t\t// in the direction of the current segment move,
\t\t\t// otherwise the same point is moved until there is 
\t\t\t// a segment direction change
\t\t\tif (currentOrientation != lastOrientation)
\t\t\t{
\t\t\t\tcurrentIndex++;
\t\t\t\t// Copy the previous way point into the new one
\t\t\t\t// We can't base the new position on index - 1
\t\t\t\t// because sometime elbows turn out not to exist,
\t\t\t\t// then we'd have to rewind.
\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][0] = mxEdgeStyle.wayPoints1[currentIndex - 1][0];
\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][1] = mxEdgeStyle.wayPoints1[currentIndex - 1][1];
\t\t\t}

\t\t\tvar tar = (routePattern[i] & mxEdgeStyle.TARGET_MASK) > 0;
\t\t\tvar sou = (routePattern[i] & mxEdgeStyle.SOURCE_MASK) > 0;
\t\t\tvar side = (routePattern[i] & mxEdgeStyle.SIDE_MASK) >> 5;
\t\t\tside = side << quad;

\t\t\tif (side > 0xF)
\t\t\t{
\t\t\t\tside = side >> 4;
\t\t\t}

\t\t\tvar center = (routePattern[i] & mxEdgeStyle.CENTER_MASK) > 0;

\t\t\tif ((sou || tar) && side < 9)
\t\t\t{
\t\t\t\tvar limit = 0;
\t\t\t\tvar souTar = sou ? 0 : 1;

\t\t\t\tif (center && currentOrientation == 0)
\t\t\t\t{
\t\t\t\t\tlimit = geo[souTar][0] + constraint[souTar][0] * geo[souTar][2];
\t\t\t\t}
\t\t\t\telse if (center)
\t\t\t\t{
\t\t\t\t\tlimit = geo[souTar][1] + constraint[souTar][1] * geo[souTar][3];
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tlimit = mxEdgeStyle.limits[souTar][side];
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (currentOrientation == 0)
\t\t\t\t{
\t\t\t\t\tvar lastX = mxEdgeStyle.wayPoints1[currentIndex][0];
\t\t\t\t\tvar deltaX = (limit - lastX) * direction[0];

\t\t\t\t\tif (deltaX > 0)
\t\t\t\t\t{
\t\t\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][0] += direction[0]
\t\t\t\t\t\t\t\t* deltaX;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar lastY = mxEdgeStyle.wayPoints1[currentIndex][1];
\t\t\t\t\tvar deltaY = (limit - lastY) * direction[1];

\t\t\t\t\tif (deltaY > 0)
\t\t\t\t\t{
\t\t\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][1] += direction[1]
\t\t\t\t\t\t\t\t* deltaY;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\telse if (center)
\t\t\t{
\t\t\t\t// Which center we're travelling to depend on the current direction
\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][0] += direction[0]
\t\t\t\t\t\t* Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2);
\t\t\t\tmxEdgeStyle.wayPoints1[currentIndex][1] += direction[1]
\t\t\t\t\t\t* Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2);
\t\t\t}

\t\t\tif (currentIndex > 0
\t\t\t\t\t&& mxEdgeStyle.wayPoints1[currentIndex][currentOrientation] == mxEdgeStyle.wayPoints1[currentIndex - 1][currentOrientation])
\t\t\t{
\t\t\t\tcurrentIndex--;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tlastOrientation = currentOrientation;
\t\t\t}
\t\t}

\t\tfor (var i = 0; i <= currentIndex; i++)
\t\t{
\t\t\tif (i == currentIndex)
\t\t\t{
\t\t\t\t// Last point can cause last segment to be in
\t\t\t\t// same direction as jetty/approach. If so,
\t\t\t\t// check the number of points is consistent
\t\t\t\t// with the relative orientation of source and target
\t\t\t\t// jx. Same orientation requires an even
\t\t\t\t// number of turns (points), different requires
\t\t\t\t// odd.
\t\t\t\tvar targetOrientation = (dir[1] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0
\t\t\t\t\t\t: 1;
\t\t\t\tvar sameOrient = targetOrientation == initialOrientation ? 0 : 1;

\t\t\t\t// (currentIndex + 1) % 2 is 0 for even number of points,
\t\t\t\t// 1 for odd
\t\t\t\tif (sameOrient != (currentIndex + 1) % 2)
\t\t\t\t{
\t\t\t\t\t// The last point isn't required
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tresult.push(new mxPoint(Math.round(mxEdgeStyle.wayPoints1[i][0] * state.view.scale * 10) / 10,
\t\t\t\t\t\t\t\t\tMath.round(mxEdgeStyle.wayPoints1[i][1] * state.view.scale * 10) / 10));
\t\t}
\t\t
\t\t//console.log(result);

\t\t// Removes duplicates
\t\tvar index = 1;
\t\t
\t\twhile (index < result.length)
\t\t{
\t\t\tif (result[index - 1] == null || result[index] == null ||
\t\t\t\tresult[index - 1].x != result[index].x ||
\t\t\t\tresult[index - 1].y != result[index].y)
\t\t\t{
\t\t\t\tindex++;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult.splice(index, 1);
\t\t\t}
\t\t}
\t},
\t
\tgetRoutePattern: function(dir, quad, dx, dy)
\t{
\t\tvar sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3
\t\t\t\t: dir[0];
\t\tvar targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3
\t\t\t\t: dir[1];

\t\tsourceIndex -= quad;
\t\ttargetIndex -= quad;

\t\tif (sourceIndex < 1)
\t\t{
\t\t\tsourceIndex += 4;
\t\t}
\t\tif (targetIndex < 1)
\t\t{
\t\t\ttargetIndex += 4;
\t\t}

\t\tvar result = routePatterns[sourceIndex - 1][targetIndex - 1];

\t\tif (dx == 0 || dy == 0)
\t\t{
\t\t\tif (inlineRoutePatterns[sourceIndex - 1][targetIndex - 1] != null)
\t\t\t{
\t\t\t\tresult = inlineRoutePatterns[sourceIndex - 1][targetIndex - 1];
\t\t\t}
\t\t}

\t\treturn result;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxStyleRegistry =
{
\t/**
\t * Class: mxStyleRegistry
\t *
\t * Singleton class that acts as a global converter from string to object values
\t * in a style. This is currently only used to perimeters and edge styles.
\t * 
\t * Variable: values
\t *
\t * Maps from strings to objects.
\t */
\tvalues: [],

\t/**
\t * Function: putValue
\t *
\t * Puts the given object into the registry under the given name.
\t */
\tputValue: function(name, obj)
\t{
\t\tmxStyleRegistry.values[name] = obj;
\t},

\t/**
\t * Function: getValue
\t *
\t * Returns the value associated with the given name.
\t */
\tgetValue: function(name)
\t{
\t\treturn mxStyleRegistry.values[name];
\t},
\t
\t/**
\t * Function: getName
\t * 
\t * Returns the name for the given value.
\t */
\tgetName: function(value)
\t{
\t\tfor (var key in mxStyleRegistry.values)
\t\t{
\t\t\tif (mxStyleRegistry.values[key] == value)
\t\t\t{
\t\t\t\treturn key;
\t\t\t}
\t\t}
\t\t
\t\treturn null;
\t}

};

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);
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphView
 *
 * Extends <mxEventSource> to implement a view for a graph. This class is in
 * charge of computing the absolute coordinates for the relative child
 * geometries, the points for perimeters and edge styles and keeping them
 * cached in <mxCellStates> for faster retrieval. The states are updated
 * whenever the model or the view state (translate, scale) changes. The scale
 * and translate are honoured in the bounds.
 * 
 * Event: mxEvent.UNDO
 * 
 * Fires after the root was changed in <setCurrentRoot>. The <code>edit</code>
 * property contains the <mxUndoableEdit> which contains the
 * <mxCurrentRootChange>.
 * 
 * Event: mxEvent.SCALE_AND_TRANSLATE
 * 
 * Fires after the scale and translate have been changed in <scaleAndTranslate>.
 * The <code>scale</code>, <code>previousScale</code>, <code>translate</code>
 * and <code>previousTranslate</code> properties contain the new and previous
 * scale and translate, respectively.
 * 
 * Event: mxEvent.SCALE
 * 
 * Fires after the scale was changed in <setScale>. The <code>scale</code> and
 * <code>previousScale</code> properties contain the new and previous scale.
 * 
 * Event: mxEvent.TRANSLATE
 * 
 * Fires after the translate was changed in <setTranslate>. The
 * <code>translate</code> and <code>previousTranslate</code> properties contain
 * the new and previous value for translate.
 * 
 * Event: mxEvent.DOWN and mxEvent.UP
 * 
 * Fire if the current root is changed by executing an <mxCurrentRootChange>.
 * The event name depends on the location of the root in the cell hierarchy
 * with respect to the current root. The <code>root</code> and
 * <code>previous</code> properties contain the new and previous root,
 * respectively.
 * 
 * Constructor: mxGraphView
 *
 * Constructs a new view for the given <mxGraph>.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxGraphView(graph)
{
\tthis.graph = graph;
\tthis.translate = new mxPoint();
\tthis.graphBounds = new mxRectangle();
\tthis.states = new mxDictionary();
};

/**
 * Extends mxEventSource.
 */
mxGraphView.prototype = new mxEventSource();
mxGraphView.prototype.constructor = mxGraphView;

/**
 *
 */
mxGraphView.prototype.EMPTY_POINT = new mxPoint();

/**
 * Variable: doneResource
 * 
 * Specifies the resource key for the status message after a long operation.
 * If the resource for this key does not exist then the value is used as
 * the status message. Default is 'done'.
 */
mxGraphView.prototype.doneResource = (mxClient.language != 'none') ? 'done' : '';

/**
 * Function: updatingDocumentResource
 *
 * Specifies the resource key for the status message while the document is
 * being updated. If the resource for this key does not exist then the
 * value is used as the status message. Default is 'updatingDocument'.
 */
mxGraphView.prototype.updatingDocumentResource = (mxClient.language != 'none') ? 'updatingDocument' : '';

/**
 * Variable: allowEval
 * 
 * Specifies if string values in cell styles should be evaluated using
 * <mxUtils.eval>. This will only be used if the string values can't be mapped
 * to objects using <mxStyleRegistry>. Default is false. NOTE: Enabling this
 * switch carries a possible security risk.
 */
mxGraphView.prototype.allowEval = false;

/**
 * Variable: captureDocumentGesture
 * 
 * Specifies if a gesture should be captured when it goes outside of the
 * graph container. Default is true.
 */
mxGraphView.prototype.captureDocumentGesture = true;

/**
 * Variable: optimizeVmlReflows
 * 
 * Specifies if the <canvas> should be hidden while rendering in IE8 standards
 * mode and quirks mode. This will significantly improve rendering performance.
 * Default is true.
 */
mxGraphView.prototype.optimizeVmlReflows = true;

/**
 * Variable: rendering
 * 
 * Specifies if shapes should be created, updated and destroyed using the
 * methods of <mxCellRenderer> in <graph>. Default is true.
 */
mxGraphView.prototype.rendering = true;

/**
 * Variable: graph
 *
 * Reference to the enclosing <mxGraph>.
 */
mxGraphView.prototype.graph = null;

/**
 * Variable: currentRoot
 *
 * <mxCell> that acts as the root of the displayed cell hierarchy.
 */
mxGraphView.prototype.currentRoot = null;

/**
 * Variable: graphBounds
 *
 * <mxRectangle> that caches the scales, translated bounds of the current view.
 */
mxGraphView.prototype.graphBounds = null;

/**
 * Variable: scale
 * 
 * Specifies the scale. Default is 1 (100%).
 */
mxGraphView.prototype.scale = 1;
\t
/**
 * Variable: translate
 *
 * <mxPoint> that specifies the current translation. Default is a new
 * empty <mxPoint>.
 */
mxGraphView.prototype.translate = null;

/**
 * Variable: states
 * 
 * <mxDictionary> that maps from cell IDs to <mxCellStates>.
 */
mxGraphView.prototype.states = null;

/**
 * Variable: updateStyle
 * 
 * Specifies if the style should be updated in each validation step. If this
 * is false then the style is only updated if the state is created or if the
 * style of the cell was changed. Default is false.
 */
mxGraphView.prototype.updateStyle = false;

/**
 * Variable: lastNode
 * 
 * During validation, this contains the last DOM node that was processed.
 */
mxGraphView.prototype.lastNode = null;

/**
 * Variable: lastHtmlNode
 * 
 * During validation, this contains the last HTML DOM node that was processed.
 */
mxGraphView.prototype.lastHtmlNode = null;

/**
 * Variable: lastForegroundNode
 * 
 * During validation, this contains the last edge's DOM node that was processed.
 */
mxGraphView.prototype.lastForegroundNode = null;

/**
 * Variable: lastForegroundHtmlNode
 * 
 * During validation, this contains the last edge HTML DOM node that was processed.
 */
mxGraphView.prototype.lastForegroundHtmlNode = null;

/**
 * Function: getGraphBounds
 *
 * Returns <graphBounds>.
 */
mxGraphView.prototype.getGraphBounds = function()
{
\treturn this.graphBounds;
};

/**
 * Function: setGraphBounds
 *
 * Sets <graphBounds>.
 */
mxGraphView.prototype.setGraphBounds = function(value)
{
\tthis.graphBounds = value;
};

/**
 * Function: getBounds
 * 
 * Returns the union of all <mxCellStates> for the given array of <mxCells>.
 *
 * Parameters:
 *
 * cells - Array of <mxCells> whose bounds should be returned.
 */
mxGraphView.prototype.getBounds = function(cells)
{
\tvar result = null;
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tvar model = this.graph.getModel();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (model.isVertex(cells[i]) || model.isEdge(cells[i]))
\t\t\t{
\t\t\t\tvar state = this.getState(cells[i]);
\t\t\t
\t\t\t\tif (state != null)
\t\t\t\t{
\t\t\t\t\tif (result == null)
\t\t\t\t\t{
\t\t\t\t\t\tresult = mxRectangle.fromRectangle(state);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tresult.add(state);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: setCurrentRoot
 *
 * Sets and returns the current root and fires an <undo> event before
 * calling <mxGraph.sizeDidChange>.
 *
 * Parameters:
 *
 * root - <mxCell> that specifies the root of the displayed cell hierarchy.
 */
mxGraphView.prototype.setCurrentRoot = function(root)
{
\tif (this.currentRoot != root)
\t{
\t\tvar change = new mxCurrentRootChange(this, root);
\t\tchange.execute();
\t\tvar edit = new mxUndoableEdit(this, true);
\t\tedit.add(change);
\t\tthis.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
\t\tthis.graph.sizeDidChange();
\t}
\t
\treturn root;
};

/**
 * Function: scaleAndTranslate
 *
 * Sets the scale and translation and fires a <scale> and <translate> event
 * before calling <revalidate> followed by <mxGraph.sizeDidChange>.
 *
 * Parameters:
 *
 * scale - Decimal value that specifies the new scale (1 is 100%).
 * dx - X-coordinate of the translation.
 * dy - Y-coordinate of the translation.
 */
mxGraphView.prototype.scaleAndTranslate = function(scale, dx, dy)
{
\tvar previousScale = this.scale;
\tvar previousTranslate = new mxPoint(this.translate.x, this.translate.y);
\t
\tif (this.scale != scale || this.translate.x != dx || this.translate.y != dy)
\t{
\t\tthis.scale = scale;
\t\t
\t\tthis.translate.x = dx;
\t\tthis.translate.y = dy;

\t\tif (this.isEventsEnabled())
\t\t{
\t\t\tthis.viewStateChanged();
\t\t}
\t}
\t
\tthis.fireEvent(new mxEventObject(mxEvent.SCALE_AND_TRANSLATE,
\t\t'scale', scale, 'previousScale', previousScale,
\t\t'translate', this.translate, 'previousTranslate', previousTranslate));
};

/**
 * Function: getScale
 * 
 * Returns the <scale>.
 */
mxGraphView.prototype.getScale = function()
{
\treturn this.scale;
};

/**
 * Function: setScale
 *
 * Sets the scale and fires a <scale> event before calling <revalidate> followed
 * by <mxGraph.sizeDidChange>.
 *
 * Parameters:
 *
 * value - Decimal value that specifies the new scale (1 is 100%).
 */
mxGraphView.prototype.setScale = function(value)
{
\tvar previousScale = this.scale;
\t
\tif (this.scale != value)
\t{
\t\tthis.scale = value;

\t\tif (this.isEventsEnabled())
\t\t{
\t\t\tthis.viewStateChanged();
\t\t}
\t}
\t
\tthis.fireEvent(new mxEventObject(mxEvent.SCALE,
\t\t'scale', value, 'previousScale', previousScale));
};

/**
 * Function: getTranslate
 * 
 * Returns the <translate>.
 */
mxGraphView.prototype.getTranslate = function()
{
\treturn this.translate;
};

/**
 * Function: setTranslate
 *
 * Sets the translation and fires a <translate> event before calling
 * <revalidate> followed by <mxGraph.sizeDidChange>. The translation is the
 * negative of the origin.
 *
 * Parameters:
 *
 * dx - X-coordinate of the translation.
 * dy - Y-coordinate of the translation.
 */
mxGraphView.prototype.setTranslate = function(dx, dy)
{
\tvar previousTranslate = new mxPoint(this.translate.x, this.translate.y);
\t
\tif (this.translate.x != dx || this.translate.y != dy)
\t{
\t\tthis.translate.x = dx;
\t\tthis.translate.y = dy;

\t\tif (this.isEventsEnabled())
\t\t{
\t\t\tthis.viewStateChanged();
\t\t}
\t}
\t
\tthis.fireEvent(new mxEventObject(mxEvent.TRANSLATE,
\t\t'translate', this.translate, 'previousTranslate', previousTranslate));
};

/**
 * Function: viewStateChanged
 * 
 * Invoked after <scale> and/or <translate> has changed.
 */
mxGraphView.prototype.viewStateChanged = function()
{
\tthis.revalidate();
\tthis.graph.sizeDidChange();
};

/**
 * Function: refresh
 *
 * Clears the view if <currentRoot> is not null and revalidates.
 */
mxGraphView.prototype.refresh = function()
{
\tif (this.currentRoot != null)
\t{
\t\tthis.clear();
\t}
\t
\tthis.revalidate();
};

/**
 * Function: revalidate
 *
 * Revalidates the complete view with all cell states.
 */
mxGraphView.prototype.revalidate = function()
{
\tthis.invalidate();
\tthis.validate();
};

/**
 * Function: clear
 *
 * Removes the state of the given cell and all descendants if the given
 * cell is not the current root.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> for which the state should be removed. Default
 * is the root of the model.
 * force - Boolean indicating if the current root should be ignored for
 * recursion.
 */
mxGraphView.prototype.clear = function(cell, force, recurse)
{
\tvar model = this.graph.getModel();
\tcell = cell || model.getRoot();
\tforce = (force != null) ? force : false;
\trecurse = (recurse != null) ? recurse : true;
\t
\tthis.removeState(cell);
\t
\tif (recurse && (force || cell != this.currentRoot))
\t{
\t\tvar childCount = model.getChildCount(cell);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tthis.clear(model.getChildAt(cell, i), force);
\t\t}
\t}
\telse
\t{
\t\tthis.invalidate(cell);
\t}
};

/**
 * Function: invalidate
 * 
 * Invalidates the state of the given cell, all its descendants and
 * connected edges.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> to be invalidated. Default is the root of the
 * model.
 */
mxGraphView.prototype.invalidate = function(cell, recurse, includeEdges)
{
\tvar model = this.graph.getModel();
\tcell = cell || model.getRoot();
\trecurse = (recurse != null) ? recurse : true;
\tincludeEdges = (includeEdges != null) ? includeEdges : true;
\t
\tvar state = this.getState(cell);
\t
\tif (state != null)
\t{
\t\tstate.invalid = true;
\t}
\t
\t// Avoids infinite loops for invalid graphs
\tif (!cell.invalidating)
\t{
\t\tcell.invalidating = true;
\t\t
\t\t// Recursively invalidates all descendants
\t\tif (recurse)
\t\t{
\t\t\tvar childCount = model.getChildCount(cell);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tvar child = model.getChildAt(cell, i);
\t\t\t\tthis.invalidate(child, recurse, includeEdges);
\t\t\t}
\t\t}
\t\t
\t\t// Propagates invalidation to all connected edges
\t\tif (includeEdges)
\t\t{
\t\t\tvar edgeCount = model.getEdgeCount(cell);
\t\t\t
\t\t\tfor (var i = 0; i < edgeCount; i++)
\t\t\t{
\t\t\t\tthis.invalidate(model.getEdgeAt(cell, i), recurse, includeEdges);
\t\t\t}
\t\t}
\t\t
\t\tdelete cell.invalidating;
\t}
};

/**
 * Function: validate
 * 
 * Calls <validateCell> and <validateCellState> and updates the <graphBounds>
 * using <getBoundingBox>. Finally the background is validated using
 * <validateBackground>.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> to be used as the root of the validation.
 * Default is <currentRoot> or the root of the model.
 */
mxGraphView.prototype.validate = function(cell)
{
\tvar t0 = mxLog.enter('mxGraphView.validate');
\twindow.status = mxResources.get(this.updatingDocumentResource) ||
\t\tthis.updatingDocumentResource;
\t
\tthis.resetValidationState();
\t
\t// Improves IE rendering speed by minimizing reflows
\tvar prevDisplay = null;
\t
\tif (this.optimizeVmlReflows && this.canvas != null && this.textDiv == null &&
\t\t((document.documentMode == 8 && !mxClient.IS_EM) || mxClient.IS_QUIRKS))
\t{
\t\t// Placeholder keeps scrollbar positions when canvas is hidden
\t\tthis.placeholder = document.createElement('div');
\t\tthis.placeholder.style.position = 'absolute';
\t\tthis.placeholder.style.width = this.canvas.clientWidth + 'px';
\t\tthis.placeholder.style.height = this.canvas.clientHeight + 'px';
\t\tthis.canvas.parentNode.appendChild(this.placeholder);

\t\tprevDisplay = this.drawPane.style.display;
\t\tthis.canvas.style.display = 'none';
\t\t
\t\t// Creates temporary DIV used for text measuring in mxText.updateBoundingBox
\t\tthis.textDiv = document.createElement('div');
\t\tthis.textDiv.style.position = 'absolute';
\t\tthis.textDiv.style.whiteSpace = 'nowrap';
\t\tthis.textDiv.style.visibility = 'hidden';
\t\tthis.textDiv.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
\t\tthis.textDiv.style.zoom = '1';
\t\t
\t\tdocument.body.appendChild(this.textDiv);
\t}
\t
\tvar graphBounds = this.getBoundingBox(this.validateCellState(
\t\tthis.validateCell(cell || ((this.currentRoot != null) ?
\t\t\tthis.currentRoot : this.graph.getModel().getRoot()))));
\tthis.setGraphBounds((graphBounds != null) ? graphBounds : this.getEmptyBounds());
\tthis.validateBackground();
\t
\tif (prevDisplay != null)
\t{
\t\tthis.canvas.style.display = prevDisplay;
\t\tthis.textDiv.parentNode.removeChild(this.textDiv);
\t\t
\t\tif (this.placeholder != null)
\t\t{
\t\t\tthis.placeholder.parentNode.removeChild(this.placeholder);
\t\t}
\t\t\t\t
\t\t// Textdiv cannot be reused
\t\tthis.textDiv = null;
\t}
\t
\tthis.resetValidationState();
\t
\twindow.status = mxResources.get(this.doneResource) ||
\t\tthis.doneResource;
\tmxLog.leave('mxGraphView.validate', t0);
};

/**
 * Function: getEmptyBounds
 * 
 * Returns the bounds for an empty graph. This returns a rectangle at
 * <translate> with the size of 0 x 0.
 */
mxGraphView.prototype.getEmptyBounds = function()
{
\treturn new mxRectangle(this.translate.x * this.scale, this.translate.y * this.scale);
};

/**
 * Function: getBoundingBox
 * 
 * Returns the bounding box of the shape and the label for the given
 * <mxCellState> and its children if recurse is true.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose bounding box should be returned.
 * recurse - Optional boolean indicating if the children should be included.
 * Default is true.
 */
mxGraphView.prototype.getBoundingBox = function(state, recurse)
{
\trecurse = (recurse != null) ? recurse : true;
\tvar bbox = null;
\t
\tif (state != null)
\t{
\t\tif (state.shape != null && state.shape.boundingBox != null)
\t\t{
\t\t\tbbox = state.shape.boundingBox.clone();
\t\t}
\t\t
\t\t// Adds label bounding box to graph bounds
\t\tif (state.text != null && state.text.boundingBox != null)
\t\t{
\t\t\tif (bbox != null)
\t\t\t{
\t\t\t\tbbox.add(state.text.boundingBox);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tbbox = state.text.boundingBox.clone();
\t\t\t}
\t\t}
\t\t
\t\tif (recurse)
\t\t{
\t\t\tvar model = this.graph.getModel();
\t\t\tvar childCount = model.getChildCount(state.cell);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tvar bounds = this.getBoundingBox(this.getState(model.getChildAt(state.cell, i)));
\t\t\t\t
\t\t\t\tif (bounds != null)
\t\t\t\t{
\t\t\t\t\tif (bbox == null)
\t\t\t\t\t{
\t\t\t\t\t\tbbox = bounds;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tbbox.add(bounds);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn bbox;
};

/**
 * Function: createBackgroundPageShape
 *
 * Creates and returns the shape used as the background page.
 * 
 * Parameters:
 * 
 * bounds - <mxRectangle> that represents the bounds of the shape.
 */
mxGraphView.prototype.createBackgroundPageShape = function(bounds)
{
\treturn new mxRectangleShape(bounds, 'white', 'black');
};

/**
 * Function: validateBackground
 *
 * Calls <validateBackgroundImage> and <validateBackgroundPage>.
 */
mxGraphView.prototype.validateBackground = function()
{
\tthis.validateBackgroundImage();
\tthis.validateBackgroundPage();
};

/**
 * Function: validateBackgroundImage
 * 
 * Validates the background image.
 */
mxGraphView.prototype.validateBackgroundImage = function()
{
\tvar bg = this.graph.getBackgroundImage();
\t
\tif (bg != null)
\t{
\t\tif (this.backgroundImage == null || this.backgroundImage.image != bg.src)
\t\t{
\t\t\tif (this.backgroundImage != null)
\t\t\t{
\t\t\t\tthis.backgroundImage.destroy();
\t\t\t}
\t\t\t
\t\t\tvar bounds = new mxRectangle(0, 0, 1, 1);
\t\t\t
\t\t\tthis.backgroundImage = new mxImageShape(bounds, bg.src);
\t\t\tthis.backgroundImage.dialect = this.graph.dialect;
\t\t\tthis.backgroundImage.init(this.backgroundPane);
\t\t\tthis.backgroundImage.redraw();

\t\t\t// Workaround for ignored event on background in IE8 standards mode
\t\t\tif (document.documentMode == 8 && !mxClient.IS_EM)
\t\t\t{
\t\t\t\tmxEvent.addGestureListeners(this.backgroundImage.node,
\t\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t\t{
\t\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
\t\t\t\t\t}),
\t\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t\t{
\t\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
\t\t\t\t\t}),
\t\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t\t{
\t\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
\t\t\t\t\t})
\t\t\t\t);
\t\t\t}
\t\t}
\t\t
\t\tthis.redrawBackgroundImage(this.backgroundImage, bg);
\t}
\telse if (this.backgroundImage != null)
\t{
\t\tthis.backgroundImage.destroy();
\t\tthis.backgroundImage = null;
\t}
};

/**
 * Function: validateBackgroundPage
 * 
 * Validates the background page.
 */
mxGraphView.prototype.validateBackgroundPage = function()
{
\tif (this.graph.pageVisible)
\t{
\t\tvar bounds = this.getBackgroundPageBounds();
\t\t
\t\tif (this.backgroundPageShape == null)
\t\t{
\t\t\tthis.backgroundPageShape = this.createBackgroundPageShape(bounds);
\t\t\tthis.backgroundPageShape.scale = this.scale;
\t\t\tthis.backgroundPageShape.isShadow = true;
\t\t\tthis.backgroundPageShape.dialect = this.graph.dialect;
\t\t\tthis.backgroundPageShape.init(this.backgroundPane);
\t\t\tthis.backgroundPageShape.redraw();
\t\t\t
\t\t\t// Adds listener for double click handling on background
\t\t\tif (this.graph.nativeDblClickEnabled)
\t\t\t{
\t\t\t\tmxEvent.addListener(this.backgroundPageShape.node, 'dblclick', mxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tthis.graph.dblClick(evt);
\t\t\t\t}));
\t\t\t}

\t\t\t// Adds basic listeners for graph event dispatching outside of the
\t\t\t// container and finishing the handling of a single gesture
\t\t\tmxEvent.addGestureListeners(this.backgroundPageShape.node,
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
\t\t\t\t}),
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\t// Hides the tooltip if mouse is outside container
\t\t\t\t\tif (this.graph.tooltipHandler != null && this.graph.tooltipHandler.isHideOnHover())
\t\t\t\t\t{
\t\t\t\t\t\tthis.graph.tooltipHandler.hide();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (this.graph.isMouseDown && !mxEvent.isConsumed(evt))
\t\t\t\t\t{
\t\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
\t\t\t\t\t}
\t\t\t\t}),
\t\t\t\tmxUtils.bind(this, function(evt)
\t\t\t\t{
\t\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
\t\t\t\t})
\t\t\t);
\t\t}
\t\telse
\t\t{
\t\t\tthis.backgroundPageShape.scale = this.scale;
\t\t\tthis.backgroundPageShape.bounds = bounds;
\t\t\tthis.backgroundPageShape.redraw();
\t\t}
\t}
\telse if (this.backgroundPageShape != null)
\t{
\t\tthis.backgroundPageShape.destroy();
\t\tthis.backgroundPageShape = null;
\t}
};

/**
 * Function: getBackgroundPageBounds
 * 
 * Returns the bounds for the background page.
 */
mxGraphView.prototype.getBackgroundPageBounds = function()
{
\tvar fmt = this.graph.pageFormat;
\tvar ps = this.scale * this.graph.pageScale;
\tvar bounds = new mxRectangle(this.scale * this.translate.x, this.scale * this.translate.y,
\t\t\tfmt.width * ps, fmt.height * ps);
\t
\treturn bounds;
};

/**
 * Function: redrawBackgroundImage
 *
 * Updates the bounds and redraws the background image.
 * 
 * Example:
 * 
 * If the background image should not be scaled, this can be replaced with
 * the following.
 * 
 * (code)
 * mxGraphView.prototype.redrawBackground = function(backgroundImage, bg)
 * {
 *   backgroundImage.bounds.x = this.translate.x;
 *   backgroundImage.bounds.y = this.translate.y;
 *   backgroundImage.bounds.width = bg.width;
 *   backgroundImage.bounds.height = bg.height;
 *
 *   backgroundImage.redraw();
 * };
 * (end)
 * 
 * Parameters:
 * 
 * backgroundImage - <mxImageShape> that represents the background image.
 * bg - <mxImage> that specifies the image and its dimensions.
 */
mxGraphView.prototype.redrawBackgroundImage = function(backgroundImage, bg)
{
\tbackgroundImage.scale = this.scale;
\tbackgroundImage.bounds.x = this.scale * this.translate.x;
\tbackgroundImage.bounds.y = this.scale * this.translate.y;
\tbackgroundImage.bounds.width = this.scale * bg.width;
\tbackgroundImage.bounds.height = this.scale * bg.height;

\tbackgroundImage.redraw();
};

/**
 * Function: validateCell
 * 
 * Recursively creates the cell state for the given cell if visible is true and
 * the given cell is visible. If the cell is not visible but the state exists
 * then it is removed using <removeState>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose <mxCellState> should be created.
 * visible - Optional boolean indicating if the cell should be visible. Default
 * is true.
 */
mxGraphView.prototype.validateCell = function(cell, visible)
{
\tvisible = (visible != null) ? visible : true;
\t
\tif (cell != null)
\t{
\t\tvisible = visible && this.graph.isCellVisible(cell);
\t\tvar state = this.getState(cell, visible);
\t\t
\t\tif (state != null && !visible)
\t\t{
\t\t\tthis.removeState(cell);
\t\t}
\t\telse
\t\t{
\t\t\tvar model = this.graph.getModel();
\t\t\tvar childCount = model.getChildCount(cell);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tthis.validateCell(model.getChildAt(cell, i), visible &&
\t\t\t\t\t(!this.isCellCollapsed(cell) || cell == this.currentRoot));
\t\t\t}
\t\t}
\t}
\t
\treturn cell;
};

/**
 * Function: validateCellState
 * 
 * Validates and repaints the <mxCellState> for the given <mxCell>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose <mxCellState> should be validated.
 * recurse - Optional boolean indicating if the children of the cell should be
 * validated. Default is true.
 */
mxGraphView.prototype.validateCellState = function(cell, recurse)
{
\trecurse = (recurse != null) ? recurse : true;
\tvar state = null;
\t
\tif (cell != null)
\t{
\t\tstate = this.getState(cell);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tvar model = this.graph.getModel();
\t\t\t
\t\t\tif (state.invalid)
\t\t\t{
\t\t\t\tstate.invalid = false;
\t\t\t\t
\t\t\t\tif (state.style == null || state.invalidStyle)
\t\t\t\t{
\t\t\t\t\tstate.style = this.graph.getCellStyle(state.cell);
\t\t\t\t\tstate.invalidStyle = false;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (cell != this.currentRoot)
\t\t\t\t{
\t\t\t\t\tthis.validateCellState(model.getParent(cell), false);
\t\t\t\t}

\t\t\t\tstate.setVisibleTerminalState(this.validateCellState(this.getVisibleTerminal(cell, true), false), true);
\t\t\t\tstate.setVisibleTerminalState(this.validateCellState(this.getVisibleTerminal(cell, false), false), false);
\t\t\t\t
\t\t\t\tthis.updateCellState(state);
\t\t\t\t
\t\t\t\t// Repaint happens immediately after the cell is validated
\t\t\t\tif (cell != this.currentRoot && !state.invalid)
\t\t\t\t{
\t\t\t\t\tthis.graph.cellRenderer.redraw(state, false, this.isRendering());

\t\t\t\t\t// Handles changes to invertex paintbounds after update of rendering shape
\t\t\t\t\tstate.updateCachedBounds();
\t\t\t\t}
\t\t\t}

\t\t\tif (recurse && !state.invalid)
\t\t\t{
\t\t\t\t// Updates order in DOM if recursively traversing
\t\t\t\tif (state.shape != null)
\t\t\t\t{
\t\t\t\t\tthis.stateValidated(state);
\t\t\t\t}
\t\t\t
\t\t\t\tvar childCount = model.getChildCount(cell);
\t\t\t\t
\t\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t\t{
\t\t\t\t\tthis.validateCellState(model.getChildAt(cell, i));
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn state;
};

/**
 * Function: updateCellState
 * 
 * Updates the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to be updated.
 */
mxGraphView.prototype.updateCellState = function(state)
{
\tstate.absoluteOffset.x = 0;
\tstate.absoluteOffset.y = 0;
\tstate.origin.x = 0;
\tstate.origin.y = 0;
\tstate.length = 0;
\t
\tif (state.cell != this.currentRoot)
\t{
\t\tvar model = this.graph.getModel();
\t\tvar pState = this.getState(model.getParent(state.cell)); 
\t\t
\t\tif (pState != null && pState.cell != this.currentRoot)
\t\t{
\t\t\tstate.origin.x += pState.origin.x;
\t\t\tstate.origin.y += pState.origin.y;
\t\t}
\t\t
\t\tvar offset = this.graph.getChildOffsetForCell(state.cell);
\t\t
\t\tif (offset != null)
\t\t{
\t\t\tstate.origin.x += offset.x;
\t\t\tstate.origin.y += offset.y;
\t\t}
\t\t
\t\tvar geo = this.graph.getCellGeometry(state.cell);\t\t\t\t
\t
\t\tif (geo != null)
\t\t{
\t\t\tif (!model.isEdge(state.cell))
\t\t\t{
\t\t\t\toffset = (geo.offset != null) ? geo.offset : this.EMPTY_POINT;
\t
\t\t\t\tif (geo.relative && pState != null)
\t\t\t\t{
\t\t\t\t\tif (model.isEdge(pState.cell))
\t\t\t\t\t{
\t\t\t\t\t\tvar origin = this.getPoint(pState, geo);

\t\t\t\t\t\tif (origin != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tstate.origin.x += (origin.x / this.scale) - pState.origin.x - this.translate.x;
\t\t\t\t\t\t\tstate.origin.y += (origin.y / this.scale) - pState.origin.y - this.translate.y;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tstate.origin.x += geo.x * pState.unscaledWidth + offset.x;
\t\t\t\t\t\tstate.origin.y += geo.y * pState.unscaledHeight + offset.y;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tstate.absoluteOffset.x = this.scale * offset.x;
\t\t\t\t\tstate.absoluteOffset.y = this.scale * offset.y;
\t\t\t\t\tstate.origin.x += geo.x;
\t\t\t\t\tstate.origin.y += geo.y;
\t\t\t\t}
\t\t\t}
\t
\t\t\tstate.x = this.scale * (this.translate.x + state.origin.x);
\t\t\tstate.y = this.scale * (this.translate.y + state.origin.y);
\t\t\tstate.width = this.scale * geo.width;
\t\t\tstate.unscaledWidth = geo.width;
\t\t\tstate.height = this.scale * geo.height;
\t\t\tstate.unscaledHeight = geo.height;
\t\t\t
\t\t\tif (model.isVertex(state.cell))
\t\t\t{
\t\t\t\tthis.updateVertexState(state, geo);
\t\t\t}
\t\t\t
\t\t\tif (model.isEdge(state.cell))
\t\t\t{
\t\t\t\tthis.updateEdgeState(state, geo);
\t\t\t}
\t\t}
\t}

\tstate.updateCachedBounds();
};

/**
 * Function: isCellCollapsed
 * 
 * Returns true if the children of the given cell should not be visible in the
 * view. This implementation uses <mxGraph.isCellVisible> but it can be
 * overidden to use a separate condition.
 */
mxGraphView.prototype.isCellCollapsed = function(cell)
{
\treturn this.graph.isCellCollapsed(cell);
};

/**
 * Function: updateVertexState
 * 
 * Validates the given cell state.
 */
mxGraphView.prototype.updateVertexState = function(state, geo)
{
\tvar model = this.graph.getModel();
\tvar pState = this.getState(model.getParent(state.cell));
\t
\tif (geo.relative && pState != null && !model.isEdge(pState.cell))
\t{
\t\tvar alpha = mxUtils.toRadians(pState.style[mxConstants.STYLE_ROTATION] || '0');
\t\t
\t\tif (alpha != 0)
\t\t{
\t\t\tvar cos = Math.cos(alpha);
\t\t\tvar sin = Math.sin(alpha);

\t\t\tvar ct = new mxPoint(state.getCenterX(), state.getCenterY());
\t\t\tvar cx = new mxPoint(pState.getCenterX(), pState.getCenterY());
\t\t\tvar pt = mxUtils.getRotatedPoint(ct, cos, sin, cx);
\t\t\tstate.x = pt.x - state.width / 2;
\t\t\tstate.y = pt.y - state.height / 2;
\t\t}
\t}
\t
\tthis.updateVertexLabelOffset(state);
};

/**
 * Function: updateEdgeState
 * 
 * Validates the given cell state.
 */
mxGraphView.prototype.updateEdgeState = function(state, geo)
{
\tvar source = state.getVisibleTerminalState(true);
\tvar target = state.getVisibleTerminalState(false);
\t
\t// This will remove edges with no terminals and no terminal points
\t// as such edges are invalid and produce NPEs in the edge styles.
\t// Also removes connected edges that have no visible terminals.
\tif ((this.graph.model.getTerminal(state.cell, true) != null && source == null) ||
\t\t(source == null && geo.getTerminalPoint(true) == null) ||
\t\t(this.graph.model.getTerminal(state.cell, false) != null && target == null) ||
\t\t(target == null && geo.getTerminalPoint(false) == null))
\t{
\t\tthis.clear(state.cell, true);
\t}
\telse
\t{
\t\tthis.updateFixedTerminalPoints(state, source, target);
\t\tthis.updatePoints(state, geo.points, source, target);
\t\tthis.updateFloatingTerminalPoints(state, source, target);
\t\t
\t\tvar pts = state.absolutePoints;
\t\t
\t\tif (state.cell != this.currentRoot && (pts == null || pts.length < 2 ||
\t\t\tpts[0] == null || pts[pts.length - 1] == null))
\t\t{
\t\t\t// This will remove edges with invalid points from the list of states in the view.
\t\t\t// Happens if the one of the terminals and the corresponding terminal point is null.
\t\t\tthis.clear(state.cell, true);
\t\t}
\t\telse
\t\t{
\t\t\tthis.updateEdgeBounds(state);
\t\t\tthis.updateEdgeLabelOffset(state);
\t\t}
\t}
};

/**
 * Function: updateVertexLabelOffset
 * 
 * Updates the absoluteOffset of the given vertex cell state. This takes
 * into account the label position styles.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose absolute offset should be updated.
 */
mxGraphView.prototype.updateVertexLabelOffset = function(state)
{
\tvar h = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);

\tif (h == mxConstants.ALIGN_LEFT)
\t{
\t\tvar lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
\t\t
\t\tif (lw != null)
\t\t{
\t\t\tlw *= this.scale;
\t\t}
\t\telse
\t\t{
\t\t\tlw = state.width;
\t\t}
\t\t
\t\tstate.absoluteOffset.x -= lw;
\t}
\telse if (h == mxConstants.ALIGN_RIGHT)
\t{
\t\tstate.absoluteOffset.x += state.width;
\t}
\telse if (h == mxConstants.ALIGN_CENTER)
\t{
\t\tvar lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
\t\t
\t\tif (lw != null)
\t\t{
\t\t\t// Aligns text block with given width inside the vertex width
\t\t\tvar align = mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
\t\t\tvar dx = 0;
\t\t\t
\t\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t\t{
\t\t\t\tdx = 0.5;
\t\t\t}
\t\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t\t{
\t\t\t\tdx = 1;
\t\t\t}
\t\t\t
\t\t\tif (dx != 0)
\t\t\t{
\t\t\t\tstate.absoluteOffset.x -= (lw * this.scale - state.width) * dx;
\t\t\t}
\t\t}
\t}
\t
\tvar v = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
\t
\tif (v == mxConstants.ALIGN_TOP)
\t{
\t\tstate.absoluteOffset.y -= state.height;
\t}
\telse if (v == mxConstants.ALIGN_BOTTOM)
\t{
\t\tstate.absoluteOffset.y += state.height;
\t}
};

/**
 * Function: resetValidationState
 *
 * Resets the current validation state.
 */
mxGraphView.prototype.resetValidationState = function()
{
\tthis.lastNode = null;
\tthis.lastHtmlNode = null;
\tthis.lastForegroundNode = null;
\tthis.lastForegroundHtmlNode = null;
};

/**
 * Function: stateValidated
 * 
 * Invoked when a state has been processed in <validatePoints>. This is used
 * to update the order of the DOM nodes of the shape.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the cell state.
 */
mxGraphView.prototype.stateValidated = function(state)
{
\tvar fg = (this.graph.getModel().isEdge(state.cell) && this.graph.keepEdgesInForeground) ||
\t\t(this.graph.getModel().isVertex(state.cell) && this.graph.keepEdgesInBackground);
\tvar htmlNode = (fg) ? this.lastForegroundHtmlNode || this.lastHtmlNode : this.lastHtmlNode;
\tvar node = (fg) ? this.lastForegroundNode || this.lastNode : this.lastNode;
\tvar result = this.graph.cellRenderer.insertStateAfter(state, node, htmlNode);

\tif (fg)
\t{
\t\tthis.lastForegroundHtmlNode = result[1];
\t\tthis.lastForegroundNode = result[0];
\t}
\telse
\t{
\t\tthis.lastHtmlNode = result[1];
\t\tthis.lastNode = result[0];
\t}
};

/**
 * Function: updateFixedTerminalPoints
 *
 * Sets the initial absolute terminal points in the given state before the edge
 * style is computed.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose initial terminal points should be updated.
 * source - <mxCellState> which represents the source terminal.
 * target - <mxCellState> which represents the target terminal.
 */
mxGraphView.prototype.updateFixedTerminalPoints = function(edge, source, target)
{
\tthis.updateFixedTerminalPoint(edge, source, true,
\t\tthis.graph.getConnectionConstraint(edge, source, true));
\tthis.updateFixedTerminalPoint(edge, target, false,
\t\tthis.graph.getConnectionConstraint(edge, target, false));
};

/**
 * Function: updateFixedTerminalPoint
 *
 * Sets the fixed source or target terminal point on the given edge.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose terminal point should be updated.
 * terminal - <mxCellState> which represents the actual terminal.
 * source - Boolean that specifies if the terminal is the source.
 * constraint - <mxConnectionConstraint> that specifies the connection.
 */
mxGraphView.prototype.updateFixedTerminalPoint = function(edge, terminal, source, constraint)
{
\tedge.setAbsoluteTerminalPoint(this.getFixedTerminalPoint(edge, terminal, source, constraint), source);
};

/**
 * Function: getFixedTerminalPoint
 *
 * Returns the fixed source or target terminal point for the given edge.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose terminal point should be returned.
 * terminal - <mxCellState> which represents the actual terminal.
 * source - Boolean that specifies if the terminal is the source.
 * constraint - <mxConnectionConstraint> that specifies the connection.
 */
mxGraphView.prototype.getFixedTerminalPoint = function(edge, terminal, source, constraint)
{
\tvar pt = null;
\t
\tif (constraint != null)
\t{
\t\tpt = this.graph.getConnectionPoint(terminal, constraint, false); // FIXME Rounding introduced bugs when calculating label positions -> , this.graph.isOrthogonal(edge));
\t}
\t
\tif (pt == null && terminal == null)
\t{
\t\tvar s = this.scale;
\t\tvar tr = this.translate;
\t\tvar orig = edge.origin;
\t\tvar geo = this.graph.getCellGeometry(edge.cell);
\t\tpt = geo.getTerminalPoint(source);
\t\t
\t\tif (pt != null)
\t\t{
\t\t\tpt = new mxPoint(s * (tr.x + pt.x + orig.x),
\t\t\t\t\t\t\t s * (tr.y + pt.y + orig.y));
\t\t}
\t}
\t
\treturn pt;
};

/**
 * Function: updateBoundsFromStencil
 * 
 * Updates the bounds of the given cell state to reflect the bounds of the stencil
 * if it has a fixed aspect and returns the previous bounds as an <mxRectangle> if
 * the bounds have been modified or null otherwise.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose bounds should be updated.
 */
mxGraphView.prototype.updateBoundsFromStencil = function(state)
{
\tvar previous = null;
\t
\tif (state != null && state.shape != null && state.shape.stencil != null && state.shape.stencil.aspect == 'fixed')
\t{
\t\tprevious = mxRectangle.fromRectangle(state);
\t\tvar asp = state.shape.stencil.computeAspect(state.style, state.x, state.y, state.width, state.height);
\t\tstate.setRect(asp.x, asp.y, state.shape.stencil.w0 * asp.width, state.shape.stencil.h0 * asp.height);
\t}
\t
\treturn previous;
};

/**
 * Function: updatePoints
 *
 * Updates the absolute points in the given state using the specified array
 * of <mxPoints> as the relative points.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose absolute points should be updated.
 * points - Array of <mxPoints> that constitute the relative points.
 * source - <mxCellState> that represents the source terminal.
 * target - <mxCellState> that represents the target terminal.
 */
mxGraphView.prototype.updatePoints = function(edge, points, source, target)
{
\tif (edge != null)
\t{
\t\tvar pts = [];
\t\tpts.push(edge.absolutePoints[0]);
\t\tvar edgeStyle = this.getEdgeStyle(edge, points, source, target);
\t\t
\t\tif (edgeStyle != null)
\t\t{
\t\t\tvar src = this.getTerminalPort(edge, source, true);
\t\t\tvar trg = this.getTerminalPort(edge, target, false);
\t\t\t
\t\t\t// Uses the stencil bounds for routing and restores after routing
\t\t\tvar srcBounds = this.updateBoundsFromStencil(src);
\t\t\tvar trgBounds = this.updateBoundsFromStencil(trg);

\t\t\tedgeStyle(edge, src, trg, points, pts);
\t\t\t
\t\t\t// Restores previous bounds
\t\t\tif (srcBounds != null)
\t\t\t{
\t\t\t\tsrc.setRect(srcBounds.x, srcBounds.y, srcBounds.width, srcBounds.height);
\t\t\t}
\t\t\t
\t\t\tif (trgBounds != null)
\t\t\t{
\t\t\t\ttrg.setRect(trgBounds.x, trgBounds.y, trgBounds.width, trgBounds.height);
\t\t\t}
\t\t}
\t\telse if (points != null)
\t\t{
\t\t\tfor (var i = 0; i < points.length; i++)
\t\t\t{
\t\t\t\tif (points[i] != null)
\t\t\t\t{
\t\t\t\t\tvar pt = mxUtils.clone(points[i]);
\t\t\t\t\tpts.push(this.transformControlPoint(edge, pt));
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tvar tmp = edge.absolutePoints;
\t\tpts.push(tmp[tmp.length-1]);

\t\tedge.absolutePoints = pts;
\t}
};

/**
 * Function: transformControlPoint
 *
 * Transforms the given control point to an absolute point.
 */
mxGraphView.prototype.transformControlPoint = function(state, pt, ignoreScale)
{
\tif (state != null && pt != null)
\t{
\t\tvar orig = state.origin;
\t\tvar scale = ignoreScale ? 1 : this.scale
\t\t
\t    return new mxPoint(scale * (pt.x + this.translate.x + orig.x),
\t    \t\tscale * (pt.y + this.translate.y + orig.y));
\t}
\t
\treturn null;
};

/**
 * Function: isLoopStyleEnabled
 * 
 * Returns true if the given edge should be routed with <mxGraph.defaultLoopStyle>
 * or the <mxConstants.STYLE_LOOP> defined for the given edge. This implementation
 * returns true if the given edge is a loop and does not have connections constraints
 * associated.
 */
mxGraphView.prototype.isLoopStyleEnabled = function(edge, points, source, target)
{
\tvar sc = this.graph.getConnectionConstraint(edge, source, true);
\tvar tc = this.graph.getConnectionConstraint(edge, target, false);
\t
\tif ((points == null || points.length < 2) &&
\t\t(!mxUtils.getValue(edge.style, mxConstants.STYLE_ORTHOGONAL_LOOP, false) ||
\t\t((sc == null || sc.point == null) && (tc == null || tc.point == null))))
\t{
\t\treturn source != null && source == target;
\t}
\t
\treturn false;
};

/**
 * Function: getEdgeStyle
 * 
 * Returns the edge style function to be used to render the given edge state.
 */
mxGraphView.prototype.getEdgeStyle = function(edge, points, source, target)
{
\tvar edgeStyle = this.isLoopStyleEnabled(edge, points, source, target) ?
\t\tmxUtils.getValue(edge.style, mxConstants.STYLE_LOOP, this.graph.defaultLoopStyle) :
\t\t(!mxUtils.getValue(edge.style, mxConstants.STYLE_NOEDGESTYLE, false) ?
\t\tedge.style[mxConstants.STYLE_EDGE] : null);

\t// Converts string values to objects
\tif (typeof(edgeStyle) == \"string\")
\t{
\t\tvar tmp = mxStyleRegistry.getValue(edgeStyle);
\t\t
\t\tif (tmp == null && this.isAllowEval())
\t\t{
 \t\t\ttmp = mxUtils.eval(edgeStyle);
\t\t}
\t\t
\t\tedgeStyle = tmp;
\t}
\t
\tif (typeof(edgeStyle) == \"function\")
\t{
\t\treturn edgeStyle;
\t}
\t
\treturn null;
};

/**
 * Function: updateFloatingTerminalPoints
 *
 * Updates the terminal points in the given state after the edge style was
 * computed for the edge.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose terminal points should be updated.
 * source - <mxCellState> that represents the source terminal.
 * target - <mxCellState> that represents the target terminal.
 */
mxGraphView.prototype.updateFloatingTerminalPoints = function(state, source, target)
{
\tvar pts = state.absolutePoints;
\tvar p0 = pts[0];
\tvar pe = pts[pts.length - 1];

\tif (pe == null && target != null)
\t{
\t\tthis.updateFloatingTerminalPoint(state, target, source, false);
\t}
\t
\tif (p0 == null && source != null)
\t{
\t\tthis.updateFloatingTerminalPoint(state, source, target, true);
\t}
};

/**
 * Function: updateFloatingTerminalPoint
 *
 * Updates the absolute terminal point in the given state for the given
 * start and end state, where start is the source if source is true.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose terminal point should be updated.
 * start - <mxCellState> for the terminal on \"this\" side of the edge.
 * end - <mxCellState> for the terminal on the other side of the edge.
 * source - Boolean indicating if start is the source terminal state.
 */
mxGraphView.prototype.updateFloatingTerminalPoint = function(edge, start, end, source)
{
\tedge.setAbsoluteTerminalPoint(this.getFloatingTerminalPoint(edge, start, end, source), source);
};

/**
 * Function: getFloatingTerminalPoint
 * 
 * Returns the floating terminal point for the given edge, start and end
 * state, where start is the source if source is true.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> whose terminal point should be returned.
 * start - <mxCellState> for the terminal on \"this\" side of the edge.
 * end - <mxCellState> for the terminal on the other side of the edge.
 * source - Boolean indicating if start is the source terminal state.
 */
mxGraphView.prototype.getFloatingTerminalPoint = function(edge, start, end, source)
{
\tstart = this.getTerminalPort(edge, start, source);
\tvar next = this.getNextPoint(edge, end, source);
\t
\tvar orth = this.graph.isOrthogonal(edge);
\tvar alpha = mxUtils.toRadians(Number(start.style[mxConstants.STYLE_ROTATION] || '0'));
\tvar center = new mxPoint(start.getCenterX(), start.getCenterY());
\t
\tif (alpha != 0)
\t{
\t\tvar cos = Math.cos(-alpha);
\t\tvar sin = Math.sin(-alpha);
\t\tnext = mxUtils.getRotatedPoint(next, cos, sin, center);
\t}
\t
\tvar border = parseFloat(edge.style[mxConstants.STYLE_PERIMETER_SPACING] || 0);
\tborder += parseFloat(edge.style[(source) ?
\t\tmxConstants.STYLE_SOURCE_PERIMETER_SPACING :
\t\tmxConstants.STYLE_TARGET_PERIMETER_SPACING] || 0);
\tvar pt = this.getPerimeterPoint(start, next, alpha == 0 && orth, border);

\tif (alpha != 0)
\t{
\t\tvar cos = Math.cos(alpha);
\t\tvar sin = Math.sin(alpha);
\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, center);
\t}

\treturn pt;
};

/**
 * Function: getTerminalPort
 * 
 * Returns an <mxCellState> that represents the source or target terminal or
 * port for the given edge.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the state of the edge.
 * terminal - <mxCellState> that represents the terminal.
 * source - Boolean indicating if the given terminal is the source terminal.
 */
mxGraphView.prototype.getTerminalPort = function(state, terminal, source)
{
\tvar key = (source) ? mxConstants.STYLE_SOURCE_PORT :
\t\tmxConstants.STYLE_TARGET_PORT;
\tvar id = mxUtils.getValue(state.style, key);
\t
\tif (id != null)
\t{
\t\tvar tmp = this.getState(this.graph.getModel().getCell(id));
\t\t
\t\t// Only uses ports where a cell state exists
\t\tif (tmp != null)
\t\t{
\t\t\tterminal = tmp;
\t\t}
\t}
\t
\treturn terminal;
};

/**
 * Function: getPerimeterPoint
 *
 * Returns an <mxPoint> that defines the location of the intersection point between
 * the perimeter and the line between the center of the shape and the given point.
 * 
 * Parameters:
 * 
 * terminal - <mxCellState> for the source or target terminal.
 * next - <mxPoint> that lies outside of the given terminal.
 * orthogonal - Boolean that specifies if the orthogonal projection onto
 * the perimeter should be returned. If this is false then the intersection
 * of the perimeter and the line between the next and the center point is
 * returned.
 * border - Optional border between the perimeter and the shape.
 */
mxGraphView.prototype.getPerimeterPoint = function(terminal, next, orthogonal, border)
{
\tvar point = null;
\t
\tif (terminal != null)
\t{
\t\tvar perimeter = this.getPerimeterFunction(terminal);
\t\t
\t\tif (perimeter != null && next != null)
\t\t{
\t\t\tvar bounds = this.getPerimeterBounds(terminal, border);

\t\t\tif (bounds.width > 0 || bounds.height > 0)
\t\t\t{
\t\t\t\tpoint = new mxPoint(next.x, next.y);
\t\t\t\tvar flipH = false;
\t\t\t\tvar flipV = false;\t
\t\t\t\t
\t\t\t\tif (this.graph.model.isVertex(terminal.cell))
\t\t\t\t{
\t\t\t\t\tflipH = mxUtils.getValue(terminal.style, mxConstants.STYLE_FLIPH, 0) == 1;
\t\t\t\t\tflipV = mxUtils.getValue(terminal.style, mxConstants.STYLE_FLIPV, 0) == 1;\t
\t
\t\t\t\t\t// Legacy support for stencilFlipH/V
\t\t\t\t\tif (terminal.shape != null && terminal.shape.stencil != null)
\t\t\t\t\t{
\t\t\t\t\t\tflipH = (mxUtils.getValue(terminal.style, 'stencilFlipH', 0) == 1) || flipH;
\t\t\t\t\t\tflipV = (mxUtils.getValue(terminal.style, 'stencilFlipV', 0) == 1) || flipV;
\t\t\t\t\t}
\t
\t\t\t\t\tif (flipH)
\t\t\t\t\t{
\t\t\t\t\t\tpoint.x = 2 * bounds.getCenterX() - point.x;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (flipV)
\t\t\t\t\t{
\t\t\t\t\t\tpoint.y = 2 * bounds.getCenterY() - point.y;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tpoint = perimeter(bounds, terminal, point, orthogonal);

\t\t\t\tif (point != null)
\t\t\t\t{
\t\t\t\t\tif (flipH)
\t\t\t\t\t{
\t\t\t\t\t\tpoint.x = 2 * bounds.getCenterX() - point.x;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (flipV)
\t\t\t\t\t{
\t\t\t\t\t\tpoint.y = 2 * bounds.getCenterY() - point.y;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (point == null)
\t\t{
\t\t\tpoint = this.getPoint(terminal);
\t\t}
\t}
\t
\treturn point;
};

/**
 * Function: getRoutingCenterX
 * 
 * Returns the x-coordinate of the center point for automatic routing.
 */
mxGraphView.prototype.getRoutingCenterX = function (state)
{
\tvar f = (state.style != null) ? parseFloat(state.style
\t\t[mxConstants.STYLE_ROUTING_CENTER_X]) || 0 : 0;

\treturn state.getCenterX() + f * state.width;
};

/**
 * Function: getRoutingCenterY
 * 
 * Returns the y-coordinate of the center point for automatic routing.
 */
mxGraphView.prototype.getRoutingCenterY = function (state)
{
\tvar f = (state.style != null) ? parseFloat(state.style
\t\t[mxConstants.STYLE_ROUTING_CENTER_Y]) || 0 : 0;

\treturn state.getCenterY() + f * state.height;
};

/**
 * Function: getPerimeterBounds
 *
 * Returns the perimeter bounds for the given terminal, edge pair as an
 * <mxRectangle>.
 * 
 * If you have a model where each terminal has a relative child that should
 * act as the graphical endpoint for a connection from/to the terminal, then
 * this method can be replaced as follows:
 * 
 * (code)
 * var oldGetPerimeterBounds = mxGraphView.prototype.getPerimeterBounds;
 * mxGraphView.prototype.getPerimeterBounds = function(terminal, edge, isSource)
 * {
 *   var model = this.graph.getModel();
 *   var childCount = model.getChildCount(terminal.cell);
 * 
 *   if (childCount > 0)
 *   {
 *     var child = model.getChildAt(terminal.cell, 0);
 *     var geo = model.getGeometry(child);
 *
 *     if (geo != null &&
 *         geo.relative)
 *     {
 *       var state = this.getState(child);
 *       
 *       if (state != null)
 *       {
 *         terminal = state;
 *       }
 *     }
 *   }
 *   
 *   return oldGetPerimeterBounds.apply(this, arguments);
 * };
 * (end)
 * 
 * Parameters:
 * 
 * terminal - <mxCellState> that represents the terminal.
 * border - Number that adds a border between the shape and the perimeter.
 */
mxGraphView.prototype.getPerimeterBounds = function(terminal, border)
{
\tborder = (border != null) ? border : 0;

\tif (terminal != null)
\t{
\t\tborder += parseFloat(terminal.style[mxConstants.STYLE_PERIMETER_SPACING] || 0);
\t}

\treturn terminal.getPerimeterBounds(border * this.scale);
};

/**
 * Function: getPerimeterFunction
 *
 * Returns the perimeter function for the given state.
 */
mxGraphView.prototype.getPerimeterFunction = function(state)
{
\tvar perimeter = state.style[mxConstants.STYLE_PERIMETER];

\t// Converts string values to objects
\tif (typeof(perimeter) == \"string\")
\t{
\t\tvar tmp = mxStyleRegistry.getValue(perimeter);
\t\t
\t\tif (tmp == null && this.isAllowEval())
\t\t{
 \t\t\ttmp = mxUtils.eval(perimeter);
\t\t}

\t\tperimeter = tmp;
\t}
\t
\tif (typeof(perimeter) == \"function\")
\t{
\t\treturn perimeter;
\t}
\t
\treturn null;
};

/**
 * Function: getNextPoint
 *
 * Returns the nearest point in the list of absolute points or the center
 * of the opposite terminal.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> that represents the edge.
 * opposite - <mxCellState> that represents the opposite terminal.
 * source - Boolean indicating if the next point for the source or target
 * should be returned.
 */
mxGraphView.prototype.getNextPoint = function(edge, opposite, source)
{
\tvar pts = edge.absolutePoints;
\tvar point = null;
\t
\tif (pts != null && pts.length >= 2)
\t{
\t\tvar count = pts.length;
\t\tpoint = pts[(source) ? Math.min(1, count - 1) : Math.max(0, count - 2)];
\t}
\t
\tif (point == null && opposite != null)
\t{
\t\tpoint = new mxPoint(opposite.getCenterX(), opposite.getCenterY());
\t}
\t
\treturn point;
};

/**
 * Function: getVisibleTerminal
 *
 * Returns the nearest ancestor terminal that is visible. The edge appears
 * to be connected to this terminal on the display. The result of this method
 * is cached in <mxCellState.getVisibleTerminalState>.
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose visible terminal should be returned.
 * source - Boolean that specifies if the source or target terminal
 * should be returned.
 */
mxGraphView.prototype.getVisibleTerminal = function(edge, source)
{
\tvar model = this.graph.getModel();
\tvar result = model.getTerminal(edge, source);
\tvar best = result;
\t
\twhile (result != null && result != this.currentRoot)
\t{
\t\tif (!this.graph.isCellVisible(best) || this.isCellCollapsed(result))
\t\t{
\t\t\tbest = result;
\t\t}
\t\t
\t\tresult = model.getParent(result);
\t}

\t// Checks if the result is valid for the current view state
\tif (best != null && (!model.contains(best) ||
\t\tmodel.getParent(best) == model.getRoot() ||
\t\tbest == this.currentRoot))
\t{
\t\tbest = null;
\t}
\t
\treturn best;
};

/**
 * Function: updateEdgeBounds
 *
 * Updates the given state using the bounding box of t
 * he absolute points.
 * Also updates <mxCellState.terminalDistance>, <mxCellState.length> and
 * <mxCellState.segments>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose bounds should be updated.
 */
mxGraphView.prototype.updateEdgeBounds = function(state)
{
\tvar points = state.absolutePoints;
\tvar p0 = points[0];
\tvar pe = points[points.length - 1];
\t
\tif (p0.x != pe.x || p0.y != pe.y)
\t{
\t\tvar dx = pe.x - p0.x;
\t\tvar dy = pe.y - p0.y;
\t\tstate.terminalDistance = Math.sqrt(dx * dx + dy * dy);
\t}
\telse
\t{
\t\tstate.terminalDistance = 0;
\t}
\t
\tvar length = 0;
\tvar segments = [];
\tvar pt = p0;
\t
\tif (pt != null)
\t{
\t\tvar minX = pt.x;
\t\tvar minY = pt.y;
\t\tvar maxX = minX;
\t\tvar maxY = minY;
\t\t
\t\tfor (var i = 1; i < points.length; i++)
\t\t{
\t\t\tvar tmp = points[i];
\t\t\t
\t\t\tif (tmp != null)
\t\t\t{
\t\t\t\tvar dx = pt.x - tmp.x;
\t\t\t\tvar dy = pt.y - tmp.y;
\t\t\t\t
\t\t\t\tvar segment = Math.sqrt(dx * dx + dy * dy);
\t\t\t\tsegments.push(segment);
\t\t\t\tlength += segment;
\t\t\t\t
\t\t\t\tpt = tmp;
\t\t\t\t
\t\t\t\tminX = Math.min(pt.x, minX);
\t\t\t\tminY = Math.min(pt.y, minY);
\t\t\t\tmaxX = Math.max(pt.x, maxX);
\t\t\t\tmaxY = Math.max(pt.y, maxY);
\t\t\t}
\t\t}
\t\t
\t\tstate.length = length;
\t\tstate.segments = segments;
\t\t
\t\tvar markerSize = 1; // TODO: include marker size
\t\t
\t\tstate.x = minX;
\t\tstate.y = minY;
\t\tstate.width = Math.max(markerSize, maxX - minX);
\t\tstate.height = Math.max(markerSize, maxY - minY);
\t}
};

/**
 * Function: getPoint
 *
 * Returns the absolute point on the edge for the given relative
 * <mxGeometry> as an <mxPoint>. The edge is represented by the given
 * <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the state of the parent edge.
 * geometry - <mxGeometry> that represents the relative location.
 */
mxGraphView.prototype.getPoint = function(state, geometry)
{
\tvar x = state.getCenterX();
\tvar y = state.getCenterY();
\t
\tif (state.segments != null && (geometry == null || geometry.relative))
\t{
\t\tvar gx = (geometry != null) ? geometry.x / 2 : 0;
\t\tvar pointCount = state.absolutePoints.length;
\t\tvar dist = Math.round((gx + 0.5) * state.length);
\t\tvar segment = state.segments[0];
\t\tvar length = 0;\t\t\t\t
\t\tvar index = 1;

\t\twhile (dist >= Math.round(length + segment) && index < pointCount - 1)
\t\t{
\t\t\tlength += segment;
\t\t\tsegment = state.segments[index++];
\t\t}

\t\tvar factor = (segment == 0) ? 0 : (dist - length) / segment;
\t\tvar p0 = state.absolutePoints[index-1];
\t\tvar pe = state.absolutePoints[index];

\t\tif (p0 != null && pe != null)
\t\t{
\t\t\tvar gy = 0;
\t\t\tvar offsetX = 0;
\t\t\tvar offsetY = 0;

\t\t\tif (geometry != null)
\t\t\t{
\t\t\t\tgy = geometry.y;
\t\t\t\tvar offset = geometry.offset;
\t\t\t\t
\t\t\t\tif (offset != null)
\t\t\t\t{
\t\t\t\t\toffsetX = offset.x;
\t\t\t\t\toffsetY = offset.y;
\t\t\t\t}
\t\t\t}

\t\t\tvar dx = pe.x - p0.x;
\t\t\tvar dy = pe.y - p0.y;
\t\t\tvar nx = (segment == 0) ? 0 : dy / segment;
\t\t\tvar ny = (segment == 0) ? 0 : dx / segment;
\t\t\t
\t\t\tx = p0.x + dx * factor + (nx * gy + offsetX) * this.scale;
\t\t\ty = p0.y + dy * factor - (ny * gy - offsetY) * this.scale;
\t\t}
\t}
\telse if (geometry != null)
\t{
\t\tvar offset = geometry.offset;
\t\t
\t\tif (offset != null)
\t\t{
\t\t\tx += offset.x;
\t\t\ty += offset.y;
\t\t}
\t}
\t
\treturn new mxPoint(x, y);\t\t
};

/**
 * Function: getRelativePoint
 *
 * Gets the relative point that describes the given, absolute label
 * position for the given edge state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the state of the parent edge.
 * x - Specifies the x-coordinate of the absolute label location.
 * y - Specifies the y-coordinate of the absolute label location.
 */
mxGraphView.prototype.getRelativePoint = function(edgeState, x, y)
{
\tvar model = this.graph.getModel();
\tvar geometry = model.getGeometry(edgeState.cell);
\t
\tif (geometry != null)
\t{
\t\tvar pointCount = edgeState.absolutePoints.length;
\t\t
\t\tif (geometry.relative && pointCount > 1)
\t\t{
\t\t\tvar totalLength = edgeState.length;
\t\t\tvar segments = edgeState.segments;

\t\t\t// Works which line segment the point of the label is closest to
\t\t\tvar p0 = edgeState.absolutePoints[0];
\t\t\tvar pe = edgeState.absolutePoints[1];
\t\t\tvar minDist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);

\t\t\tvar index = 0;
\t\t\tvar tmp = 0;
\t\t\tvar length = 0;
\t\t\t
\t\t\tfor (var i = 2; i < pointCount; i++)
\t\t\t{
\t\t\t\ttmp += segments[i - 2];
\t\t\t\tpe = edgeState.absolutePoints[i];
\t\t\t\tvar dist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);

\t\t\t\tif (dist <= minDist)
\t\t\t\t{
\t\t\t\t\tminDist = dist;
\t\t\t\t\tindex = i - 1;
\t\t\t\t\tlength = tmp;
\t\t\t\t}
\t\t\t\t
\t\t\t\tp0 = pe;
\t\t\t}
\t\t\t
\t\t\tvar seg = segments[index];
\t\t\tp0 = edgeState.absolutePoints[index];
\t\t\tpe = edgeState.absolutePoints[index + 1];
\t\t\t
\t\t\tvar x2 = p0.x;
\t\t\tvar y2 = p0.y;
\t\t\t
\t\t\tvar x1 = pe.x;
\t\t\tvar y1 = pe.y;
\t\t\t
\t\t\tvar px = x;
\t\t\tvar py = y;
\t\t\t
\t\t\tvar xSegment = x2 - x1;
\t\t\tvar ySegment = y2 - y1;
\t\t\t
\t\t\tpx -= x1;
\t\t\tpy -= y1;
\t\t\tvar projlenSq = 0;
\t\t\t
\t\t\tpx = xSegment - px;
\t\t\tpy = ySegment - py;
\t\t\tvar dotprod = px * xSegment + py * ySegment;

\t\t\tif (dotprod <= 0.0)
\t\t\t{
\t\t\t\tprojlenSq = 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tprojlenSq = dotprod * dotprod
\t\t\t\t\t\t/ (xSegment * xSegment + ySegment * ySegment);
\t\t\t}

\t\t\tvar projlen = Math.sqrt(projlenSq);

\t\t\tif (projlen > seg)
\t\t\t{
\t\t\t\tprojlen = seg;
\t\t\t}

\t\t\tvar yDistance = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, pe
\t\t\t\t\t.x, pe.y, x, y));
\t\t\tvar direction = mxUtils.relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y);

\t\t\tif (direction == -1)
\t\t\t{
\t\t\t\tyDistance = -yDistance;
\t\t\t}

\t\t\t// Constructs the relative point for the label
\t\t\treturn new mxPoint(((totalLength / 2 - length - projlen) / totalLength) * -2,
\t\t\t\t\t\tyDistance / this.scale);
\t\t}
\t}
\t
\treturn new mxPoint();
};

/**
 * Function: updateEdgeLabelOffset
 *
 * Updates <mxCellState.absoluteOffset> for the given state. The absolute
 * offset is normally used for the position of the edge label. Is is
 * calculated from the geometry as an absolute offset from the center
 * between the two endpoints if the geometry is absolute, or as the
 * relative distance between the center along the line and the absolute
 * orthogonal distance if the geometry is relative.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose absolute offset should be updated.
 */
mxGraphView.prototype.updateEdgeLabelOffset = function(state)
{
\tvar points = state.absolutePoints;
\t
\tstate.absoluteOffset.x = state.getCenterX();
\tstate.absoluteOffset.y = state.getCenterY();

\tif (points != null && points.length > 0 && state.segments != null)
\t{
\t\tvar geometry = this.graph.getCellGeometry(state.cell);
\t\t
\t\tif (geometry.relative)
\t\t{
\t\t\tvar offset = this.getPoint(state, geometry);
\t\t\t
\t\t\tif (offset != null)
\t\t\t{
\t\t\t\tstate.absoluteOffset = offset;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar p0 = points[0];
\t\t\tvar pe = points[points.length - 1];
\t\t\t
\t\t\tif (p0 != null && pe != null)
\t\t\t{
\t\t\t\tvar dx = pe.x - p0.x;
\t\t\t\tvar dy = pe.y - p0.y;
\t\t\t\tvar x0 = 0;
\t\t\t\tvar y0 = 0;

\t\t\t\tvar off = geometry.offset;
\t\t\t\t
\t\t\t\tif (off != null)
\t\t\t\t{
\t\t\t\t\tx0 = off.x;
\t\t\t\t\ty0 = off.y;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar x = p0.x + dx / 2 + x0 * this.scale;
\t\t\t\tvar y = p0.y + dy / 2 + y0 * this.scale;
\t\t\t\t
\t\t\t\tstate.absoluteOffset.x = x;
\t\t\t\tstate.absoluteOffset.y = y;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: getState
 *
 * Returns the <mxCellState> for the given cell. If create is true, then
 * the state is created if it does not yet exist.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the <mxCellState> should be returned.
 * create - Optional boolean indicating if a new state should be created
 * if it does not yet exist. Default is false.
 */
mxGraphView.prototype.getState = function(cell, create)
{
\tcreate = create || false;
\tvar state = null;
\t
\tif (cell != null)
\t{
\t\tstate = this.states.get(cell);
\t\t
\t\tif (create && (state == null || this.updateStyle) && this.graph.isCellVisible(cell))
\t\t{
\t\t\tif (state == null)
\t\t\t{
\t\t\t\tstate = this.createState(cell);
\t\t\t\tthis.states.put(cell, state);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tstate.style = this.graph.getCellStyle(cell);
\t\t\t}
\t\t}
\t}

\treturn state;
};

/**
 * Function: isRendering
 *
 * Returns <rendering>.
 */
mxGraphView.prototype.isRendering = function()
{
\treturn this.rendering;
};

/**
 * Function: setRendering
 *
 * Sets <rendering>.
 */
mxGraphView.prototype.setRendering = function(value)
{
\tthis.rendering = value;
};

/**
 * Function: isAllowEval
 *
 * Returns <allowEval>.
 */
mxGraphView.prototype.isAllowEval = function()
{
\treturn this.allowEval;
};

/**
 * Function: setAllowEval
 *
 * Sets <allowEval>.
 */
mxGraphView.prototype.setAllowEval = function(value)
{
\tthis.allowEval = value;
};

/**
 * Function: getStates
 *
 * Returns <states>.
 */
mxGraphView.prototype.getStates = function()
{
\treturn this.states;
};

/**
 * Function: setStates
 *
 * Sets <states>.
 */
mxGraphView.prototype.setStates = function(value)
{
\tthis.states = value;
};

/**
 * Function: getCellStates
 *
 * Returns the <mxCellStates> for the given array of <mxCells>. The array
 * contains all states that are not null, that is, the returned array may
 * have less elements than the given array. If no argument is given, then
 * this returns <states>.
 */
mxGraphView.prototype.getCellStates = function(cells)
{
\tif (cells == null)
\t{
\t\treturn this.states;
\t}
\telse
\t{
\t\tvar result = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar state = this.getState(cells[i]);
\t\t\t
\t\t\tif (state != null)
\t\t\t{
\t\t\t\tresult.push(state);
\t\t\t}
\t\t}
\t\t
\t\treturn result;
\t}
};

/**
 * Function: removeState
 *
 * Removes and returns the <mxCellState> for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the <mxCellState> should be removed.
 */
mxGraphView.prototype.removeState = function(cell)
{
\tvar state = null;
\t
\tif (cell != null)
\t{
\t\tstate = this.states.remove(cell);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tthis.graph.cellRenderer.destroy(state);
\t\t\tstate.invalid = true;
\t\t\tstate.destroy();
\t\t}
\t}
\t
\treturn state;
};

/**
 * Function: createState
 *
 * Creates and returns an <mxCellState> for the given cell and initializes
 * it using <mxCellRenderer.initialize>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which a new <mxCellState> should be created.
 */
mxGraphView.prototype.createState = function(cell)
{
\treturn new mxCellState(this, cell, this.graph.getCellStyle(cell));
};

/**
 * Function: getCanvas
 *
 * Returns the DOM node that contains the background-, draw- and
 * overlay- and decoratorpanes.
 */
mxGraphView.prototype.getCanvas = function()
{
\treturn this.canvas;
};

/**
 * Function: getBackgroundPane
 *
 * Returns the DOM node that represents the background layer.
 */
mxGraphView.prototype.getBackgroundPane = function()
{
\treturn this.backgroundPane;
};

/**
 * Function: getDrawPane
 *
 * Returns the DOM node that represents the main drawing layer.
 */
mxGraphView.prototype.getDrawPane = function()
{
\treturn this.drawPane;
};

/**
 * Function: getOverlayPane
 *
 * Returns the DOM node that represents the layer above the drawing layer.
 */
mxGraphView.prototype.getOverlayPane = function()
{
\treturn this.overlayPane;
};

/**
 * Function: getDecoratorPane
 *
 * Returns the DOM node that represents the topmost drawing layer.
 */
mxGraphView.prototype.getDecoratorPane = function()
{
\treturn this.decoratorPane;
};

/**
 * Function: isContainerEvent
 * 
 * Returns true if the event origin is one of the drawing panes or
 * containers of the view.
 */
mxGraphView.prototype.isContainerEvent = function(evt)
{
\tvar source = mxEvent.getSource(evt);

\treturn (source == this.graph.container ||
\t\tsource.parentNode == this.backgroundPane ||
\t\t(source.parentNode != null &&
\t\tsource.parentNode.parentNode == this.backgroundPane) ||
\t\tsource == this.canvas.parentNode ||
\t\tsource == this.canvas ||
\t\tsource == this.backgroundPane ||
\t\tsource == this.drawPane ||
\t\tsource == this.overlayPane ||
\t\tsource == this.decoratorPane);
};

/**
 * Function: isScrollEvent
 * 
 * Returns true if the event origin is one of the scrollbars of the
 * container in IE. Such events are ignored.
 */
 mxGraphView.prototype.isScrollEvent = function(evt)
{
\tvar offset = mxUtils.getOffset(this.graph.container);
\tvar pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y);

\tvar outWidth = this.graph.container.offsetWidth;
\tvar inWidth = this.graph.container.clientWidth;

\tif (outWidth > inWidth && pt.x > inWidth + 2 && pt.x <= outWidth)
\t{
\t\treturn true;
\t}

\tvar outHeight = this.graph.container.offsetHeight;
\tvar inHeight = this.graph.container.clientHeight;
\t
\tif (outHeight > inHeight && pt.y > inHeight + 2 && pt.y <= outHeight)
\t{
\t\treturn true;
\t}
\t
\treturn false;
};

/**
 * Function: init
 *
 * Initializes the graph event dispatch loop for the specified container
 * and invokes <create> to create the required DOM nodes for the display.
 */
mxGraphView.prototype.init = function()
{
\tthis.installListeners();
\t
\t// Creates the DOM nodes for the respective display dialect
\tvar graph = this.graph;
\t
\tif (graph.dialect == mxConstants.DIALECT_SVG)
\t{
\t\tthis.createSvg();
\t}
\telse if (graph.dialect == mxConstants.DIALECT_VML)
\t{
\t\tthis.createVml();
\t}
\telse
\t{
\t\tthis.createHtml();
\t}
};

/**
 * Function: installListeners
 *
 * Installs the required listeners in the container.
 */
mxGraphView.prototype.installListeners = function()
{
\tvar graph = this.graph;
\tvar container = graph.container;
\t
\tif (container != null)
\t{
\t\t// Support for touch device gestures (eg. pinch to zoom)
\t\t// Double-tap handling is implemented in mxGraph.fireMouseEvent
\t\tif (mxClient.IS_TOUCH)
\t\t{
\t\t\tmxEvent.addListener(container, 'gesturestart', mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tgraph.fireGestureEvent(evt);
\t\t\t\tmxEvent.consume(evt);
\t\t\t}));
\t\t\t
\t\t\tmxEvent.addListener(container, 'gesturechange', mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tgraph.fireGestureEvent(evt);
\t\t\t\tmxEvent.consume(evt);
\t\t\t}));

\t\t\tmxEvent.addListener(container, 'gestureend', mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tgraph.fireGestureEvent(evt);
\t\t\t\tmxEvent.consume(evt);
\t\t\t}));
\t\t}
\t\t
\t\t// Fires event only for one pointer per gesture
\t\tvar pointerId = null;
\t\t
\t\t// Adds basic listeners for graph event dispatching
\t\tmxEvent.addGestureListeners(container, mxUtils.bind(this, function(evt)
\t\t{
\t\t\t// Condition to avoid scrollbar events starting a rubberband selection
\t\t\tif (this.isContainerEvent(evt) && ((!mxClient.IS_IE && !mxClient.IS_IE11 && !mxClient.IS_GC &&
\t\t\t\t!mxClient.IS_OP && !mxClient.IS_SF) || !this.isScrollEvent(evt)))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
\t\t\t\tpointerId = evt.pointerId;
\t\t\t}
\t\t}),
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isContainerEvent(evt) && (pointerId == null || evt.pointerId == pointerId))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
\t\t\t}
\t\t}),
\t\tmxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isContainerEvent(evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
\t\t\t}
\t\t\t
\t\t\tpointerId = null;
\t\t}));
\t\t
\t\t// Adds listener for double click handling on background, this does always
\t\t// use native event handler, we assume that the DOM of the background
\t\t// does not change during the double click
\t\tmxEvent.addListener(container, 'dblclick', mxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.isContainerEvent(evt))
\t\t\t{
\t\t\t\tgraph.dblClick(evt);
\t\t\t}
\t\t}));

\t\t// Workaround for touch events which started on some DOM node
\t\t// on top of the container, in which case the cells under the
\t\t// mouse for the move and up events are not detected.
\t\tvar getState = function(evt)
\t\t{
\t\t\tvar state = null;
\t\t\t
\t\t\t// Workaround for touch events which started on some DOM node
\t\t\t// on top of the container, in which case the cells under the
\t\t\t// mouse for the move and up events are not detected.
\t\t\tif (mxClient.IS_TOUCH)
\t\t\t{
\t\t\t\tvar x = mxEvent.getClientX(evt);
\t\t\t\tvar y = mxEvent.getClientY(evt);
\t\t\t\t
\t\t\t\t// Dispatches the drop event to the graph which
\t\t\t\t// consumes and executes the source function
\t\t\t\tvar pt = mxUtils.convertPoint(container, x, y);
\t\t\t\tstate = graph.view.getState(graph.getCellAt(pt.x, pt.y));
\t\t\t}
\t\t\t
\t\t\treturn state;
\t\t};
\t\t
\t\t// Adds basic listeners for graph event dispatching outside of the
\t\t// container and finishing the handling of a single gesture
\t\t// Implemented via graph event dispatch loop to avoid duplicate events
\t\t// in Firefox and Chrome
\t\tgraph.addMouseListener(
\t\t{
\t\t\tmouseDown: function(sender, me)
\t\t\t{
\t\t\t\tgraph.popupMenuHandler.hideMenu();
\t\t\t},
\t\t\tmouseMove: function() { },
\t\t\tmouseUp: function() { }
\t\t});
\t\t
\t\tthis.moveHandler = mxUtils.bind(this, function(evt)
\t\t{
\t\t\t// Hides the tooltip if mouse is outside container
\t\t\tif (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover())
\t\t\t{
\t\t\t\tgraph.tooltipHandler.hide();
\t\t\t}

\t\t\tif (this.captureDocumentGesture && graph.isMouseDown && graph.container != null &&
\t\t\t\t!this.isContainerEvent(evt) && graph.container.style.display != 'none' &&
\t\t\t\tgraph.container.style.visibility != 'hidden' && !mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
\t\t\t}
\t\t});
\t\t
\t\tthis.endHandler = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (this.captureDocumentGesture && graph.isMouseDown && graph.container != null &&
\t\t\t\t!this.isContainerEvent(evt) && graph.container.style.display != 'none' &&
\t\t\t\tgraph.container.style.visibility != 'hidden')
\t\t\t{
\t\t\t\tgraph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
\t\t\t}
\t\t});
\t\t
\t\tmxEvent.addGestureListeners(document, null, this.moveHandler, this.endHandler);
\t}
};

/**
 * Function: createHtml
 *
 * Creates the DOM nodes for the HTML display.
 */
mxGraphView.prototype.createHtml = function()
{
\tvar container = this.graph.container;
\t
\tif (container != null)
\t{
\t\tthis.canvas = this.createHtmlPane('100%', '100%');
\t\tthis.canvas.style.overflow = 'hidden';
\t
\t\t// Uses minimal size for inner DIVs on Canvas. This is required
\t\t// for correct event processing in IE. If we have an overlapping
\t\t// DIV then the events on the cells are only fired for labels.
\t\tthis.backgroundPane = this.createHtmlPane('1px', '1px');
\t\tthis.drawPane = this.createHtmlPane('1px', '1px');
\t\tthis.overlayPane = this.createHtmlPane('1px', '1px');
\t\tthis.decoratorPane = this.createHtmlPane('1px', '1px');
\t\t
\t\tthis.canvas.appendChild(this.backgroundPane);
\t\tthis.canvas.appendChild(this.drawPane);
\t\tthis.canvas.appendChild(this.overlayPane);
\t\tthis.canvas.appendChild(this.decoratorPane);

\t\tcontainer.appendChild(this.canvas);
\t\tthis.updateContainerStyle(container);
\t\t
\t\t// Implements minWidth/minHeight in quirks mode
\t\tif (mxClient.IS_QUIRKS)
\t\t{
\t\t\tvar onResize = mxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\tvar bounds = this.getGraphBounds();
\t\t\t\tvar width = bounds.x + bounds.width + this.graph.border;
\t\t\t\tvar height = bounds.y + bounds.height + this.graph.border;
\t\t\t\t
\t\t\t\tthis.updateHtmlCanvasSize(width, height);
\t\t\t});
\t\t\t
\t\t\tmxEvent.addListener(window, 'resize', onResize);
\t\t}
\t}
};

/**
 * Function: updateHtmlCanvasSize
 * 
 * Updates the size of the HTML canvas.
 */
mxGraphView.prototype.updateHtmlCanvasSize = function(width, height)
{
\tif (this.graph.container != null)
\t{
\t\tvar ow = this.graph.container.offsetWidth;
\t\tvar oh = this.graph.container.offsetHeight;

\t\tif (ow < width)
\t\t{
\t\t\tthis.canvas.style.width = width + 'px';
\t\t}
\t\telse
\t\t{
\t\t\tthis.canvas.style.width = '100%';
\t\t}

\t\tif (oh < height)
\t\t{
\t\t\tthis.canvas.style.height = height + 'px';
\t\t}
\t\telse
\t\t{
\t\t\tthis.canvas.style.height = '100%';
\t\t}
\t}
};

/**
 * Function: createHtmlPane
 * 
 * Creates and returns a drawing pane in HTML (DIV).
 */
mxGraphView.prototype.createHtmlPane = function(width, height)
{
\tvar pane = document.createElement('DIV');
\t
\tif (width != null && height != null)
\t{
\t\tpane.style.position = 'absolute';
\t\tpane.style.left = '0px';
\t\tpane.style.top = '0px';

\t\tpane.style.width = width;
\t\tpane.style.height = height;
\t}
\telse
\t{
\t\tpane.style.position = 'relative';
\t}
\t
\treturn pane;
};

/**
 * Function: createVml
 *
 * Creates the DOM nodes for the VML display.
 */
mxGraphView.prototype.createVml = function()
{
\tvar container = this.graph.container;

\tif (container != null)
\t{
\t\tvar width = container.offsetWidth;
\t\tvar height = container.offsetHeight;
\t\tthis.canvas = this.createVmlPane(width, height);
\t\tthis.canvas.style.overflow = 'hidden';
\t\t
\t\tthis.backgroundPane = this.createVmlPane(width, height);
\t\tthis.drawPane = this.createVmlPane(width, height);
\t\tthis.overlayPane = this.createVmlPane(width, height);
\t\tthis.decoratorPane = this.createVmlPane(width, height);
\t\t
\t\tthis.canvas.appendChild(this.backgroundPane);
\t\tthis.canvas.appendChild(this.drawPane);
\t\tthis.canvas.appendChild(this.overlayPane);
\t\tthis.canvas.appendChild(this.decoratorPane);
\t\t
\t\tcontainer.appendChild(this.canvas);
\t}
};

/**
 * Function: createVmlPane
 * 
 * Creates a drawing pane in VML (group).
 */
mxGraphView.prototype.createVmlPane = function(width, height)
{
\tvar pane = document.createElement(mxClient.VML_PREFIX + ':group');
\t
\t// At this point the width and height are potentially
\t// uninitialized. That's OK.
\tpane.style.position = 'absolute';
\tpane.style.left = '0px';
\tpane.style.top = '0px';

\tpane.style.width = width + 'px';
\tpane.style.height = height + 'px';

\tpane.setAttribute('coordsize', width + ',' + height);
\tpane.setAttribute('coordorigin', '0,0');
\t
\treturn pane;
};

/**
 * Function: createSvg
 *
 * Creates and returns the DOM nodes for the SVG display.
 */
mxGraphView.prototype.createSvg = function()
{
\tvar container = this.graph.container;
\tthis.canvas = document.createElementNS(mxConstants.NS_SVG, 'g');
\t
\t// For background image
\tthis.backgroundPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\tthis.canvas.appendChild(this.backgroundPane);

\t// Adds two layers (background is early feature)
\tthis.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\tthis.canvas.appendChild(this.drawPane);

\tthis.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\tthis.canvas.appendChild(this.overlayPane);
\t
\tthis.decoratorPane = document.createElementNS(mxConstants.NS_SVG, 'g');
\tthis.canvas.appendChild(this.decoratorPane);
\t
\tvar root = document.createElementNS(mxConstants.NS_SVG, 'svg');
\troot.style.left = '0px';
\troot.style.top = '0px';
\troot.style.width = '100%';
\troot.style.height = '100%';
\t
\t// NOTE: In standards mode, the SVG must have block layout
\t// in order for the container DIV to not show scrollbars.
\troot.style.display = 'block';
\troot.appendChild(this.canvas);
\t
\t// Workaround for scrollbars in IE11 and below
\tif (mxClient.IS_IE || mxClient.IS_IE11)
\t{
\t\troot.style.overflow = 'hidden';
\t}

\tif (container != null)
\t{
\t\tcontainer.appendChild(root);
\t\tthis.updateContainerStyle(container);
\t}
};

/**
 * Function: updateContainerStyle
 * 
 * Updates the style of the container after installing the SVG DOM elements.
 */
mxGraphView.prototype.updateContainerStyle = function(container)
{
\t// Workaround for offset of container
\tvar style = mxUtils.getCurrentStyle(container);
\t
\tif (style != null && style.position == 'static')
\t{
\t\tcontainer.style.position = 'relative';
\t}
\t
\t// Disables built-in pan and zoom in IE10 and later
\tif (mxClient.IS_POINTER)
\t{
\t\tcontainer.style.touchAction = 'none';
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the view and all its resources.
 */
mxGraphView.prototype.destroy = function()
{
\tvar root = (this.canvas != null) ? this.canvas.ownerSVGElement : null;
\t
\tif (root == null)
\t{
\t\troot = this.canvas;
\t}
\t
\tif (root != null && root.parentNode != null)
\t{
\t\tthis.clear(this.currentRoot, true);
\t\tmxEvent.removeGestureListeners(document, null, this.moveHandler, this.endHandler);
\t\tmxEvent.release(this.graph.container);
\t\troot.parentNode.removeChild(root);
\t\t
\t\tthis.moveHandler = null;
\t\tthis.endHandler = null;
\t\tthis.canvas = null;
\t\tthis.backgroundPane = null;
\t\tthis.drawPane = null;
\t\tthis.overlayPane = null;
\t\tthis.decoratorPane = null;
\t}
};

/**
 * Class: mxCurrentRootChange
 *
 * Action to change the current root in a view.
 *
 * Constructor: mxCurrentRootChange
 *
 * Constructs a change of the current root in the given view.
 */
function mxCurrentRootChange(view, root)
{
\tthis.view = view;
\tthis.root = root;
\tthis.previous = root;
\tthis.isUp = root == null;
\t
\tif (!this.isUp)
\t{
\t\tvar tmp = this.view.currentRoot;
\t\tvar model = this.view.graph.getModel();
\t\t
\t\twhile (tmp != null)
\t\t{
\t\t\tif (tmp == root)
\t\t\t{
\t\t\t\tthis.isUp = true;
\t\t\t\tbreak;
\t\t\t}
\t\t\t
\t\t\ttmp = model.getParent(tmp);
\t\t}
\t}
};

/**
 * Function: execute
 *
 * Changes the current root of the view.
 */
mxCurrentRootChange.prototype.execute = function()
{
\tvar tmp = this.view.currentRoot;
\tthis.view.currentRoot = this.previous;
\tthis.previous = tmp;

\tvar translate = this.view.graph.getTranslateForRoot(this.view.currentRoot);
\t
\tif (translate != null)
\t{
\t\tthis.view.translate = new mxPoint(-translate.x, -translate.y);
\t}

\tif (this.isUp)
\t{
\t\tthis.view.clear(this.view.currentRoot, true);
\t\tthis.view.validate();
\t}
\telse
\t{
\t\tthis.view.refresh();
\t}
\t
\tvar name = (this.isUp) ? mxEvent.UP : mxEvent.DOWN;
\tthis.view.fireEvent(new mxEventObject(name,
\t\t'root', this.view.currentRoot, 'previous', this.previous));
\tthis.isUp = !this.isUp;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraph
 *
 * Extends <mxEventSource> to implement a graph component for
 * the browser. This is the main class of the package. To activate
 * panning and connections use <setPanning> and <setConnectable>.
 * For rubberband selection you must create a new instance of
 * <mxRubberband>. The following listeners are added to
 * <mouseListeners> by default:
 * 
 * - <tooltipHandler>: <mxTooltipHandler> that displays tooltips
 * - <panningHandler>: <mxPanningHandler> for panning and popup menus
 * - <connectionHandler>: <mxConnectionHandler> for creating connections
 * - <graphHandler>: <mxGraphHandler> for moving and cloning cells
 * 
 * These listeners will be called in the above order if they are enabled.
 *
 * Background Images:
 * 
 * To display a background image, set the image, image width and
 * image height using <setBackgroundImage>. If one of the
 * above values has changed then the <view>'s <mxGraphView.validate>
 * should be invoked.
 * 
 * Cell Images:
 * 
 * To use images in cells, a shape must be specified in the default
 * vertex style (or any named style). Possible shapes are
 * <mxConstants.SHAPE_IMAGE> and <mxConstants.SHAPE_LABEL>.
 * The code to change the shape used in the default vertex style,
 * the following code is used:
 * 
 * (code)
 * var style = graph.getStylesheet().getDefaultVertexStyle();
 * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE;
 * (end)
 * 
 * For the default vertex style, the image to be displayed can be
 * specified in a cell's style using the <mxConstants.STYLE_IMAGE>
 * key and the image URL as a value, for example:
 * 
 * (code)
 * image=http://www.example.com/image.gif
 * (end)
 * 
 * For a named style, the the stylename must be the first element
 * of the cell style:
 * 
 * (code)
 * stylename;image=http://www.example.com/image.gif
 * (end)
 * 
 * A cell style can have any number of key=value pairs added, divided
 * by a semicolon as follows:
 * 
 * (code)
 * [stylename;|key=value;]
 * (end)
 *
 * Labels:
 * 
 * The cell labels are defined by <getLabel> which uses <convertValueToString>
 * if <labelsVisible> is true. If a label must be rendered as HTML markup, then
 * <isHtmlLabel> should return true for the respective cell. If all labels
 * contain HTML markup, <htmlLabels> can be set to true. NOTE: Enabling HTML
 * labels carries a possible security risk (see the section on security in
 * the manual).
 * 
 * If wrapping is needed for a label, then <isHtmlLabel> and <isWrapping> must
 * return true for the cell whose label should be wrapped. See <isWrapping> for
 * an example.
 * 
 * If clipping is needed to keep the rendering of a HTML label inside the
 * bounds of its vertex, then <isClipping> should return true for the
 * respective cell.
 * 
 * By default, edge labels are movable and vertex labels are fixed. This can be
 * changed by setting <edgeLabelsMovable> and <vertexLabelsMovable>, or by
 * overriding <isLabelMovable>.
 *
 * In-place Editing:
 * 
 * In-place editing is started with a doubleclick or by typing F2.
 * Programmatically, <edit> is used to check if the cell is editable
 * (<isCellEditable>) and call <startEditingAtCell>, which invokes
 * <mxCellEditor.startEditing>. The editor uses the value returned
 * by <getEditingValue> as the editing value.
 * 
 * After in-place editing, <labelChanged> is called, which invokes
 * <mxGraphModel.setValue>, which in turn calls
 * <mxGraphModel.valueForCellChanged> via <mxValueChange>.
 * 
 * The event that triggers in-place editing is passed through to the
 * <cellEditor>, which may take special actions depending on the type of the
 * event or mouse location, and is also passed to <getEditingValue>. The event
 * is then passed back to the event processing functions which can perform
 * specific actions based on the trigger event.
 * 
 * Tooltips:
 * 
 * Tooltips are implemented by <getTooltip>, which calls <getTooltipForCell>
 * if a cell is under the mousepointer. The default implementation checks if
 * the cell has a getTooltip function and calls it if it exists. Hence, in order
 * to provide custom tooltips, the cell must provide a getTooltip function, or 
 * one of the two above functions must be overridden.
 * 
 * Typically, for custom cell tooltips, the latter function is overridden as
 * follows:
 * 
 * (code)
 * graph.getTooltipForCell = function(cell)
 * {
 *   var label = this.convertValueToString(cell);
 *   return 'Tooltip for '+label;
 * }
 * (end)
 * 
 * When using a config file, the function is overridden in the mxGraph section
 * using the following entry:
 * 
 * (code)
 * <add as=\"getTooltipForCell\"><![CDATA[
 *   function(cell)
 *   {
 *     var label = this.convertValueToString(cell);
 *     return 'Tooltip for '+label;
 *   }
 * ]]></add>
 * (end)
 * 
 * \"this\" refers to the graph in the implementation, so for example to check if 
 * a cell is an edge, you use this.getModel().isEdge(cell)
 *
 * For replacing the default implementation of <getTooltipForCell> (rather than 
 * replacing the function on a specific instance), the following code should be 
 * used after loading the JavaScript files, but before creating a new mxGraph 
 * instance using <mxGraph>:
 * 
 * (code)
 * mxGraph.prototype.getTooltipForCell = function(cell)
 * {
 *   var label = this.convertValueToString(cell);
 *   return 'Tooltip for '+label;
 * }
 * (end)
 * 
 * Shapes & Styles:
 * 
 * The implementation of new shapes is demonstrated in the examples. We'll assume
 * that we have implemented a custom shape with the name BoxShape which we want
 * to use for drawing vertices. To use this shape, it must first be registered in
 * the cell renderer as follows:
 * 
 * (code)
 * mxCellRenderer.registerShape('box', BoxShape);
 * (end)
 * 
 * The code registers the BoxShape constructor under the name box in the cell
 * renderer of the graph. The shape can now be referenced using the shape-key in
 * a style definition. (The cell renderer contains a set of additional shapes,
 * namely one for each constant with a SHAPE-prefix in <mxConstants>.)
 *
 * Styles are a collection of key, value pairs and a stylesheet is a collection
 * of named styles. The names are referenced by the cellstyle, which is stored
 * in <mxCell.style> with the following format: [stylename;|key=value;]. The
 * string is resolved to a collection of key, value pairs, where the keys are
 * overridden with the values in the string.
 *
 * When introducing a new shape, the name under which the shape is registered
 * must be used in the stylesheet. There are three ways of doing this:
 * 
 *   - By changing the default style, so that all vertices will use the new
 * \t\tshape
 *   - By defining a new style, so that only vertices with the respective
 * \t\tcellstyle will use the new shape
 *   - By using shape=box in the cellstyle's optional list of key, value pairs
 * \t\tto be overridden
 *
 * In the first case, the code to fetch and modify the default style for
 * vertices is as follows:
 * 
 * (code)
 * var style = graph.getStylesheet().getDefaultVertexStyle();
 * style[mxConstants.STYLE_SHAPE] = 'box';
 * (end)
 * 
 * The code takes the default vertex style, which is used for all vertices that
 * do not have a specific cellstyle, and modifies the value for the shape-key
 * in-place to use the new BoxShape for drawing vertices. This is done by
 * assigning the box value in the second line, which refers to the name of the
 * BoxShape in the cell renderer.
 * 
 * In the second case, a collection of key, value pairs is created and then
 * added to the stylesheet under a new name. In order to distinguish the
 * shapename and the stylename we'll use boxstyle for the stylename:
 * 
 * (code)
 * var style = new Object();
 * style[mxConstants.STYLE_SHAPE] = 'box';
 * style[mxConstants.STYLE_STROKECOLOR] = '#000000';
 * style[mxConstants.STYLE_FONTCOLOR] = '#000000';
 * graph.getStylesheet().putCellStyle('boxstyle', style);
 * (end)
 * 
 * The code adds a new style with the name boxstyle to the stylesheet. To use
 * this style with a cell, it must be referenced from the cellstyle as follows:
 * 
 * (code)
 * var vertex = graph.insertVertex(parent, null, 'Hello, World!', 20, 20, 80, 20,
 * \t\t\t\t'boxstyle');
 * (end)
 * 
 * To summarize, each new shape must be registered in the <mxCellRenderer> with
 * a unique name. That name is then used as the value of the shape-key in a
 * default or custom style. If there are multiple custom shapes, then there
 * should be a separate style for each shape.
 * 
 * Inheriting Styles:
 * 
 * For fill-, stroke-, gradient-, font- and indicatorColors special keywords
 * can be used. The inherit keyword for one of these colors will inherit the
 * color for the same key from the parent cell. The swimlane keyword does the
 * same, but inherits from the nearest swimlane in the ancestor hierarchy.
 * Finally, the indicated keyword will use the color of the indicator as the
 * color for the given key.
 * 
 * Scrollbars:
 * 
 * The <containers> overflow CSS property defines if scrollbars are used to
 * display the graph. For values of 'auto' or 'scroll', the scrollbars will
 * be shown. Note that the <resizeContainer> flag is normally not used
 * together with scrollbars, as it will resize the container to match the
 * size of the graph after each change.
 * 
 * Multiplicities and Validation:
 * 
 * To control the possible connections in mxGraph, <getEdgeValidationError> is
 * used. The default implementation of the function uses <multiplicities>,
 * which is an array of <mxMultiplicity>. Using this class allows to establish
 * simple multiplicities, which are enforced by the graph.
 * 
 * The <mxMultiplicity> uses <mxCell.is> to determine for which terminals it
 * applies. The default implementation of <mxCell.is> works with DOM nodes (XML
 * nodes) and checks if the given type parameter matches the nodeName of the
 * node (case insensitive). Optionally, an attributename and value can be
 * specified which are also checked.
 * 
 * <getEdgeValidationError> is called whenever the connectivity of an edge
 * changes. It returns an empty string or an error message if the edge is
 * invalid or null if the edge is valid. If the returned string is not empty
 * then it is displayed as an error message.
 * 
 * <mxMultiplicity> allows to specify the multiplicity between a terminal and
 * its possible neighbors. For example, if any rectangle may only be connected
 * to, say, a maximum of two circles you can add the following rule to
 * <multiplicities>:
 * 
 * (code)
 * graph.multiplicities.push(new mxMultiplicity(
 *   true, 'rectangle', null, null, 0, 2, ['circle'],
 *   'Only 2 targets allowed',
 *   'Only shape targets allowed'));
 * (end)
 * 
 * This will display the first error message whenever a rectangle is connected
 * to more than two circles and the second error message if a rectangle is
 * connected to anything but a circle.
 * 
 * For certain multiplicities, such as a minimum of 1 connection, which cannot
 * be enforced at cell creation time (unless the cell is created together with
 * the connection), mxGraph offers <validate> which checks all multiplicities
 * for all cells and displays the respective error messages in an overlay icon
 * on the cells.
 * 
 * If a cell is collapsed and contains validation errors, a respective warning
 * icon is attached to the collapsed cell.
 * 
 * Auto-Layout:
 * 
 * For automatic layout, the <getLayout> hook is provided in <mxLayoutManager>.
 * It can be overridden to return a layout algorithm for the children of a
 * given cell.
 * 
 * Unconnected edges:
 * 
 * The default values for all switches are designed to meet the requirements of
 * general diagram drawing applications. A very typical set of settings to
 * avoid edges that are not connected is the following:
 * 
 * (code)
 * graph.setAllowDanglingEdges(false);
 * graph.setDisconnectOnMove(false);
 * (end)
 * 
 * Setting the <cloneInvalidEdges> switch to true is optional. This switch
 * controls if edges are inserted after a copy, paste or clone-drag if they are
 * invalid. For example, edges are invalid if copied or control-dragged without 
 * having selected the corresponding terminals and allowDanglingEdges is
 * false, in which case the edges will not be cloned if the switch is false.
 * 
 * Output:
 * 
 * To produce an XML representation for a diagram, the following code can be
 * used.
 * 
 * (code)
 * var enc = new mxCodec(mxUtils.createXmlDocument());
 * var node = enc.encode(graph.getModel());
 * (end)
 * 
 * This will produce an XML node than can be handled using the DOM API or
 * turned into a string representation using the following code:
 * 
 * (code)
 * var xml = mxUtils.getXml(node);
 * (end)
 * 
 * To obtain a formatted string, mxUtils.getPrettyXml can be used instead.
 * 
 * This string can now be stored in a local persistent storage (for example
 * using Google Gears) or it can be passed to a backend using mxUtils.post as
 * follows. The url variable is the URL of the Java servlet, PHP page or HTTP
 * handler, depending on the server.
 * 
 * (code)
 * var xmlString = encodeURIComponent(mxUtils.getXml(node));
 * mxUtils.post(url, 'xml='+xmlString, function(req)
 * {
 *   // Process server response using req of type mxXmlRequest
 * });
 * (end)
 * 
 * Input:
 * 
 * To load an XML representation of a diagram into an existing graph object
 * mxUtils.load can be used as follows. The url variable is the URL of the Java
 * servlet, PHP page or HTTP handler that produces the XML string.
 * 
 * (code)
 * var xmlDoc = mxUtils.load(url).getXml();
 * var node = xmlDoc.documentElement;
 * var dec = new mxCodec(node.ownerDocument);
 * dec.decode(node, graph.getModel());
 * (end)
 * 
 * For creating a page that loads the client and a diagram using a single
 * request please refer to the deployment examples in the backends.
 * 
 * Functional dependencies:
 * 
 * (see images/callgraph.png)
 * 
 * Resources:
 *
 * resources/graph - Language resources for mxGraph
 *
 * Group: Events
 * 
 * Event: mxEvent.ROOT
 * 
 * Fires if the root in the model has changed. This event has no properties.
 * 
 * Event: mxEvent.ALIGN_CELLS
 * 
 * Fires between begin- and endUpdate in <alignCells>. The <code>cells</code>
 * and <code>align</code> properties contain the respective arguments that were
 * passed to <alignCells>.
 *
 * Event: mxEvent.FLIP_EDGE
 *
 * Fires between begin- and endUpdate in <flipEdge>. The <code>edge</code>
 * property contains the edge passed to <flipEdge>.
 * 
 * Event: mxEvent.ORDER_CELLS
 * 
 * Fires between begin- and endUpdate in <orderCells>. The <code>cells</code>
 * and <code>back</code> properties contain the respective arguments that were
 * passed to <orderCells>.
 *
 * Event: mxEvent.CELLS_ORDERED
 *
 * Fires between begin- and endUpdate in <cellsOrdered>. The <code>cells</code>
 * and <code>back</code> arguments contain the respective arguments that were
 * passed to <cellsOrdered>.
 * 
 * Event: mxEvent.GROUP_CELLS
 * 
 * Fires between begin- and endUpdate in <groupCells>. The <code>group</code>,
 * <code>cells</code> and <code>border</code> arguments contain the respective
 * arguments that were passed to <groupCells>.
 * 
 * Event: mxEvent.UNGROUP_CELLS
 * 
 * Fires between begin- and endUpdate in <ungroupCells>. The <code>cells</code>
 * property contains the array of cells that was passed to <ungroupCells>.
 * 
 * Event: mxEvent.REMOVE_CELLS_FROM_PARENT
 * 
 * Fires between begin- and endUpdate in <removeCellsFromParent>. The
 * <code>cells</code> property contains the array of cells that was passed to
 * <removeCellsFromParent>.
 * 
 * Event: mxEvent.ADD_CELLS
 * 
 * Fires between begin- and endUpdate in <addCells>. The <code>cells</code>,
 * <code>parent</code>, <code>index</code>, <code>source</code> and
 * <code>target</code> properties contain the respective arguments that were
 * passed to <addCells>.
 * 
 * Event: mxEvent.CELLS_ADDED
 * 
 * Fires between begin- and endUpdate in <cellsAdded>. The <code>cells</code>,
 * <code>parent</code>, <code>index</code>, <code>source</code>,
 * <code>target</code> and <code>absolute</code> properties contain the
 * respective arguments that were passed to <cellsAdded>.
 * 
 * Event: mxEvent.REMOVE_CELLS
 * 
 * Fires between begin- and endUpdate in <removeCells>. The <code>cells</code>
 * and <code>includeEdges</code> arguments contain the respective arguments
 * that were passed to <removeCells>.
 * 
 * Event: mxEvent.CELLS_REMOVED
 * 
 * Fires between begin- and endUpdate in <cellsRemoved>. The <code>cells</code>
 * argument contains the array of cells that was removed.
 * 
 * Event: mxEvent.SPLIT_EDGE
 * 
 * Fires between begin- and endUpdate in <splitEdge>. The <code>edge</code>
 * property contains the edge to be splitted, the <code>cells</code>,
 * <code>newEdge</code>, <code>dx</code> and <code>dy</code> properties contain
 * the respective arguments that were passed to <splitEdge>.
 * 
 * Event: mxEvent.TOGGLE_CELLS
 * 
 * Fires between begin- and endUpdate in <toggleCells>. The <code>show</code>,
 * <code>cells</code> and <code>includeEdges</code> properties contain the
 * respective arguments that were passed to <toggleCells>.
 * 
 * Event: mxEvent.FOLD_CELLS
 * 
 * Fires between begin- and endUpdate in <foldCells>. The
 * <code>collapse</code>, <code>cells</code> and <code>recurse</code>
 * properties contain the respective arguments that were passed to <foldCells>.
 * 
 * Event: mxEvent.CELLS_FOLDED
 * 
 * Fires between begin- and endUpdate in cellsFolded. The
 * <code>collapse</code>, <code>cells</code> and <code>recurse</code>
 * properties contain the respective arguments that were passed to
 * <cellsFolded>.
 * 
 * Event: mxEvent.UPDATE_CELL_SIZE
 * 
 * Fires between begin- and endUpdate in <updateCellSize>. The
 * <code>cell</code> and <code>ignoreChildren</code> properties contain the
 * respective arguments that were passed to <updateCellSize>.
 * 
 * Event: mxEvent.RESIZE_CELLS
 * 
 * Fires between begin- and endUpdate in <resizeCells>. The <code>cells</code>
 * and <code>bounds</code> properties contain the respective arguments that
 * were passed to <resizeCells>.
 * 
 * Event: mxEvent.CELLS_RESIZED
 * 
 * Fires between begin- and endUpdate in <cellsResized>. The <code>cells</code>
 * and <code>bounds</code> properties contain the respective arguments that
 * were passed to <cellsResized>.
 * 
 * Event: mxEvent.MOVE_CELLS
 * 
 * Fires between begin- and endUpdate in <moveCells>. The <code>cells</code>,
 * <code>dx</code>, <code>dy</code>, <code>clone</code>, <code>target</code>
 * and <code>event</code> properties contain the respective arguments that
 * were passed to <moveCells>.
 * 
 * Event: mxEvent.CELLS_MOVED
 * 
 * Fires between begin- and endUpdate in <cellsMoved>. The <code>cells</code>,
 * <code>dx</code>, <code>dy</code> and <code>disconnect</code> properties
 * contain the respective arguments that were passed to <cellsMoved>.
 * 
 * Event: mxEvent.CONNECT_CELL
 * 
 * Fires between begin- and endUpdate in <connectCell>. The <code>edge</code>,
 * <code>terminal</code> and <code>source</code> properties contain the
 * respective arguments that were passed to <connectCell>.
 * 
 * Event: mxEvent.CELL_CONNECTED
 * 
 * Fires between begin- and endUpdate in <cellConnected>. The
 * <code>edge</code>, <code>terminal</code> and <code>source</code> properties
 * contain the respective arguments that were passed to <cellConnected>.
 * 
 * Event: mxEvent.REFRESH
 * 
 * Fires after <refresh> was executed. This event has no properties.
 *
 * Event: mxEvent.CLICK
 * 
 * Fires in <click> after a click event. The <code>event</code> property
 * contains the original mouse event and <code>cell</code> property contains
 * the cell under the mouse or null if the background was clicked.
 * 
 * Event: mxEvent.DOUBLE_CLICK
 *
 * Fires in <dblClick> after a double click. The <code>event</code> property
 * contains the original mouse event and the <code>cell</code> property
 * contains the cell under the mouse or null if the background was clicked.
 * 
 * Event: mxEvent.GESTURE
 *
 * Fires in <fireGestureEvent> after a touch gesture. The <code>event</code>
 * property contains the original gesture end event and the <code>cell</code>
 * property contains the optional cell associated with the gesture.
 *
 * Event: mxEvent.TAP_AND_HOLD
 *
 * Fires in <tapAndHold> if a tap and hold event was detected. The <code>event</code>
 * property contains the initial touch event and the <code>cell</code> property
 * contains the cell under the mouse or null if the background was clicked.
 *
 * Event: mxEvent.FIRE_MOUSE_EVENT
 *
 * Fires in <fireMouseEvent> before the mouse listeners are invoked. The
 * <code>eventName</code> property contains the event name and the
 * <code>event</code> property contains the <mxMouseEvent>.
 *
 * Event: mxEvent.SIZE
 *
 * Fires after <sizeDidChange> was executed. The <code>bounds</code> property
 * contains the new graph bounds.
 *
 * Event: mxEvent.START_EDITING
 *
 * Fires before the in-place editor starts in <startEditingAtCell>. The
 * <code>cell</code> property contains the cell that is being edited and the
 * <code>event</code> property contains the optional event argument that was
 * passed to <startEditingAtCell>.
 * 
 * Event: mxEvent.EDITING_STARTED
 *
 * Fires after the in-place editor starts in <startEditingAtCell>. The
 * <code>cell</code> property contains the cell that is being edited and the
 * <code>event</code> property contains the optional event argument that was
 * passed to <startEditingAtCell>.
 * 
 * Event: mxEvent.EDITING_STOPPED
 *
 * Fires after the in-place editor stops in <stopEditing>.
 *
 * Event: mxEvent.LABEL_CHANGED
 *
 * Fires between begin- and endUpdate in <cellLabelChanged>. The
 * <code>cell</code> property contains the cell, the <code>value</code>
 * property contains the new value for the cell, the <code>old</code> property
 * contains the old value and the optional <code>event</code> property contains
 * the mouse event that started the edit.
 * 
 * Event: mxEvent.ADD_OVERLAY
 *
 * Fires after an overlay is added in <addCellOverlay>. The <code>cell</code>
 * property contains the cell and the <code>overlay</code> property contains
 * the <mxCellOverlay> that was added.
 *
 * Event: mxEvent.REMOVE_OVERLAY
 *
 * Fires after an overlay is removed in <removeCellOverlay> and
 * <removeCellOverlays>. The <code>cell</code> property contains the cell and
 * the <code>overlay</code> property contains the <mxCellOverlay> that was
 * removed.
 * 
 * Constructor: mxGraph
 * 
 * Constructs a new mxGraph in the specified container. Model is an optional
 * mxGraphModel. If no model is provided, a new mxGraphModel instance is 
 * used as the model. The container must have a valid owner document prior 
 * to calling this function in Internet Explorer. RenderHint is a string to
 * affect the display performance and rendering in IE, but not in SVG-based 
 * browsers. The parameter is mapped to <dialect>, which may 
 * be one of <mxConstants.DIALECT_SVG> for SVG-based browsers, 
 * <mxConstants.DIALECT_STRICTHTML> for fastest display mode,
 * <mxConstants.DIALECT_PREFERHTML> for faster display mode,
 * <mxConstants.DIALECT_MIXEDHTML> for fast and <mxConstants.DIALECT_VML> 
 * for exact display mode (slowest). The dialects are defined in mxConstants.
 * The default values are DIALECT_SVG for SVG-based browsers and
 * DIALECT_MIXED for IE.
 *
 * The possible values for the renderingHint parameter are explained below:
 * 
 * fast - The parameter is based on the fact that the display performance is 
 * highly improved in IE if the VML is not contained within a VML group 
 * element. The lack of a group element only slightly affects the display while 
 * panning, but improves the performance by almost a factor of 2, while keeping 
 * the display sufficiently accurate. This also allows to render certain shapes as HTML 
 * if the display accuracy is not affected, which is implemented by 
 * <mxShape.isMixedModeHtml>. This is the default setting and is mapped to
 * DIALECT_MIXEDHTML.
 * faster - Same as fast, but more expensive shapes are avoided. This is 
 * controlled by <mxShape.preferModeHtml>. The default implementation will 
 * avoid gradients and rounded rectangles, but more significant shapes, such 
 * as rhombus, ellipse, actor and cylinder will be rendered accurately. This 
 * setting is mapped to DIALECT_PREFERHTML.
 * fastest - Almost anything will be rendered in Html. This allows for 
 * rectangles, labels and images. This setting is mapped to
 * DIALECT_STRICTHTML.
 * exact - If accurate panning is required and if the diagram is small (up
 * to 100 cells), then this value should be used. In this mode, a group is 
 * created that contains the VML. This allows for accurate panning and is 
 * mapped to DIALECT_VML.
 *
 * Example:
 * 
 * To create a graph inside a DOM node with an id of graph:
 * (code)
 * var container = document.getElementById('graph');
 * var graph = new mxGraph(container);
 * (end)
 * 
 * Parameters:
 * 
 * container - Optional DOM node that acts as a container for the graph.
 * If this is null then the container can be initialized later using
 * <init>.
 * model - Optional <mxGraphModel> that constitutes the graph data.
 * renderHint - Optional string that specifies the display accuracy and
 * performance. Default is mxConstants.DIALECT_MIXEDHTML (for IE).
 * stylesheet - Optional <mxStylesheet> to be used in the graph.
 */
function mxGraph(container, model, renderHint, stylesheet)
{
\t// Initializes the variable in case the prototype has been
\t// modified to hold some listeners (which is possible because
\t// the createHandlers call is executed regardless of the
\t// arguments passed into the ctor).
\tthis.mouseListeners = null;
\t
\t// Converts the renderHint into a dialect
\tthis.renderHint = renderHint;

\tif (mxClient.IS_SVG)
\t{
\t\tthis.dialect = mxConstants.DIALECT_SVG;
\t}
\telse if (renderHint == mxConstants.RENDERING_HINT_EXACT && mxClient.IS_VML)
\t{
\t\tthis.dialect = mxConstants.DIALECT_VML;
\t}
\telse if (renderHint == mxConstants.RENDERING_HINT_FASTEST)
\t{
\t\tthis.dialect = mxConstants.DIALECT_STRICTHTML;
\t}
\telse if (renderHint == mxConstants.RENDERING_HINT_FASTER)
\t{
\t\tthis.dialect = mxConstants.DIALECT_PREFERHTML;
\t}
\telse // default for VML
\t{
\t\tthis.dialect = mxConstants.DIALECT_MIXEDHTML;
\t}
\t
\t// Initializes the main members that do not require a container
\tthis.model = (model != null) ? model : new mxGraphModel();
\tthis.multiplicities = [];
\tthis.imageBundles = [];
\tthis.cellRenderer = this.createCellRenderer();
\tthis.setSelectionModel(this.createSelectionModel());
\tthis.setStylesheet((stylesheet != null) ? stylesheet : this.createStylesheet());
\tthis.view = this.createGraphView();
\t
\t// Adds a graph model listener to update the view
\tthis.graphModelChangeListener = mxUtils.bind(this, function(sender, evt)
\t{
\t\tthis.graphModelChanged(evt.getProperty('edit').changes);
\t});
\t
\tthis.model.addListener(mxEvent.CHANGE, this.graphModelChangeListener);

\t// Installs basic event handlers with disabled default settings.
\tthis.createHandlers();
\t
\t// Initializes the display if a container was specified
\tif (container != null)
\t{
\t\tthis.init(container);
\t}
\t
\tthis.view.revalidate();
};

/**
 * Installs the required language resources at class
 * loading time.
 */
if (mxLoadResources)
{
\tmxResources.add(mxClient.basePath + '/resources/graph');
}
else
{
\tmxClient.defaultBundles.push(mxClient.basePath + '/resources/graph');
}

/**
 * Extends mxEventSource.
 */
mxGraph.prototype = new mxEventSource();
mxGraph.prototype.constructor = mxGraph;

/**
 * Group: Variables
 */

/**
 * Variable: mouseListeners
 * 
 * Holds the mouse event listeners. See <fireMouseEvent>.
 */
mxGraph.prototype.mouseListeners = null;

/**
 * Variable: isMouseDown
 * 
 * Holds the state of the mouse button.
 */
mxGraph.prototype.isMouseDown = false;

/**
 * Variable: model
 * 
 * Holds the <mxGraphModel> that contains the cells to be displayed.
 */
mxGraph.prototype.model = null;

/**
 * Variable: view
 * 
 * Holds the <mxGraphView> that caches the <mxCellStates> for the cells.
 */
mxGraph.prototype.view = null;

/**
 * Variable: stylesheet
 * 
 * Holds the <mxStylesheet> that defines the appearance of the cells.
 * 
 * 
 * Example:
 * 
 * Use the following code to read a stylesheet into an existing graph.
 * 
 * (code)
 * var req = mxUtils.load('stylesheet.xml');
 * var root = req.getDocumentElement();
 * var dec = new mxCodec(root.ownerDocument);
 * dec.decode(root, graph.stylesheet);
 * (end)
 */
mxGraph.prototype.stylesheet = null;
\t
/**
 * Variable: selectionModel
 * 
 * Holds the <mxGraphSelectionModel> that models the current selection.
 */
mxGraph.prototype.selectionModel = null;

/**
 * Variable: cellEditor
 * 
 * Holds the <mxCellEditor> that is used as the in-place editing.
 */
mxGraph.prototype.cellEditor = null;

/**
 * Variable: cellRenderer
 * 
 * Holds the <mxCellRenderer> for rendering the cells in the graph.
 */
mxGraph.prototype.cellRenderer = null;

/**
 * Variable: multiplicities
 * 
 * An array of <mxMultiplicities> describing the allowed
 * connections in a graph.
 */
mxGraph.prototype.multiplicities = null;

/**
 * Variable: renderHint
 * 
 * RenderHint as it was passed to the constructor.
 */
mxGraph.prototype.renderHint = null;

/**
 * Variable: dialect
 * 
 * Dialect to be used for drawing the graph. Possible values are all
 * constants in <mxConstants> with a DIALECT-prefix.
 */
mxGraph.prototype.dialect = null;

/**
 * Variable: gridSize
 * 
 * Specifies the grid size. Default is 10.
 */
mxGraph.prototype.gridSize = 10;
\t
/**
 * Variable: gridEnabled
 * 
 * Specifies if the grid is enabled. This is used in <snap>. Default is
 * true.
 */
mxGraph.prototype.gridEnabled = true;

/**
 * Variable: portsEnabled
 * 
 * Specifies if ports are enabled. This is used in <cellConnected> to update
 * the respective style. Default is true.
 */
mxGraph.prototype.portsEnabled = true;

/**
 * Variable: nativeDoubleClickEnabled
 * 
 * Specifies if native double click events should be detected. Default is true.
 */
mxGraph.prototype.nativeDblClickEnabled = true;

/**
 * Variable: doubleTapEnabled
 * 
 * Specifies if double taps on touch-based devices should be handled as a
 * double click. Default is true.
 */
mxGraph.prototype.doubleTapEnabled = true;

/**
 * Variable: doubleTapTimeout
 * 
 * Specifies the timeout for double taps and non-native double clicks. Default
 * is 500 ms.
 */
mxGraph.prototype.doubleTapTimeout = 500;

/**
 * Variable: doubleTapTolerance
 * 
 * Specifies the tolerance for double taps and double clicks in quirks mode.
 * Default is 25 pixels.
 */
mxGraph.prototype.doubleTapTolerance = 25;

/**
 * Variable: lastTouchX
 * 
 * Holds the x-coordinate of the last touch event for double tap detection.
 */
mxGraph.prototype.lastTouchY = 0;

/**
 * Variable: lastTouchX
 * 
 * Holds the y-coordinate of the last touch event for double tap detection.
 */
mxGraph.prototype.lastTouchY = 0;

/**
 * Variable: lastTouchTime
 * 
 * Holds the time of the last touch event for double click detection.
 */
mxGraph.prototype.lastTouchTime = 0;

/**
 * Variable: tapAndHoldEnabled
 * 
 * Specifies if tap and hold should be used for starting connections on touch-based
 * devices. Default is true.
 */
mxGraph.prototype.tapAndHoldEnabled = true;

/**
 * Variable: tapAndHoldDelay
 * 
 * Specifies the time for a tap and hold. Default is 500 ms.
 */
mxGraph.prototype.tapAndHoldDelay = 500;

/**
 * Variable: tapAndHoldInProgress
 * 
 * True if the timer for tap and hold events is running.
 */
mxGraph.prototype.tapAndHoldInProgress = false;

/**
 * Variable: tapAndHoldValid
 * 
 * True as long as the timer is running and the touch events
 * stay within the given <tapAndHoldTolerance>.
 */
mxGraph.prototype.tapAndHoldValid = false;

/**
 * Variable: initialTouchX
 * 
 * Holds the x-coordinate of the intial touch event for tap and hold.
 */
mxGraph.prototype.initialTouchX = 0;

/**
 * Variable: initialTouchY
 * 
 * Holds the y-coordinate of the intial touch event for tap and hold.
 */
mxGraph.prototype.initialTouchY = 0;

/**
 * Variable: tolerance
 * 
 * Tolerance for a move to be handled as a single click.
 * Default is 4 pixels.
 */
mxGraph.prototype.tolerance = 4;

/**
 * Variable: defaultOverlap
 * 
 * Value returned by <getOverlap> if <isAllowOverlapParent> returns
 * true for the given cell. <getOverlap> is used in <constrainChild> if
 * <isConstrainChild> returns true. The value specifies the
 * portion of the child which is allowed to overlap the parent.
 */
mxGraph.prototype.defaultOverlap = 0.5;

/**
 * Variable: defaultParent
 * 
 * Specifies the default parent to be used to insert new cells.
 * This is used in <getDefaultParent>. Default is null.
 */
mxGraph.prototype.defaultParent = null;

/**
 * Variable: alternateEdgeStyle
 * 
 * Specifies the alternate edge style to be used if the main control point
 * on an edge is being doubleclicked. Default is null.
 */
mxGraph.prototype.alternateEdgeStyle = null;

/**
 * Variable: backgroundImage
 *
 * Specifies the <mxImage> to be returned by <getBackgroundImage>. Default
 * is null.
 * 
 * Example:
 *
 * (code)
 * var img = new mxImage('http://www.example.com/maps/examplemap.jpg', 1024, 768);
 * graph.setBackgroundImage(img);
 * graph.view.validate();
 * (end)
 */
mxGraph.prototype.backgroundImage = null;

/**
 * Variable: pageVisible
 *
 * Specifies if the background page should be visible. Default is false.
 * Not yet implemented.
 */
mxGraph.prototype.pageVisible = false;

/**
 * Variable: pageBreaksVisible
 * 
 * Specifies if a dashed line should be drawn between multiple pages. Default
 * is false. If you change this value while a graph is being displayed then you
 * should call <sizeDidChange> to force an update of the display.
 */
mxGraph.prototype.pageBreaksVisible = false;

/**
 * Variable: pageBreakColor
 * 
 * Specifies the color for page breaks. Default is 'gray'.
 */
mxGraph.prototype.pageBreakColor = 'gray';

/**
 * Variable: pageBreakDashed
 * 
 * Specifies the page breaks should be dashed. Default is true.
 */
mxGraph.prototype.pageBreakDashed = true;

/**
 * Variable: minPageBreakDist
 * 
 * Specifies the minimum distance for page breaks to be visible. Default is
 * 20 (in pixels).
 */
mxGraph.prototype.minPageBreakDist = 20;

/**
 * Variable: preferPageSize
 * 
 * Specifies if the graph size should be rounded to the next page number in
 * <sizeDidChange>. This is only used if the graph container has scrollbars.
 * Default is false.
 */
mxGraph.prototype.preferPageSize = false;

/**
 * Variable: pageFormat
 *
 * Specifies the page format for the background page. Default is
 * <mxConstants.PAGE_FORMAT_A4_PORTRAIT>. This is used as the default in
 * <mxPrintPreview> and for painting the background page if <pageVisible> is
 * true and the pagebreaks if <pageBreaksVisible> is true.
 */
mxGraph.prototype.pageFormat = mxConstants.PAGE_FORMAT_A4_PORTRAIT;

/**
 * Variable: pageScale
 *
 * Specifies the scale of the background page. Default is 1.5.
 * Not yet implemented.
 */
mxGraph.prototype.pageScale = 1.5;

/**
 * Variable: enabled
 * 
 * Specifies the return value for <isEnabled>. Default is true.
 */
mxGraph.prototype.enabled = true;

/**
 * Variable: escapeEnabled
 * 
 * Specifies if <mxKeyHandler> should invoke <escape> when the escape key
 * is pressed. Default is true.
 */
mxGraph.prototype.escapeEnabled = true;

/**
 * Variable: invokesStopCellEditing
 * 
 * If true, when editing is to be stopped by way of selection changing,
 * data in diagram changing or other means stopCellEditing is invoked, and
 * changes are saved. This is implemented in a focus handler in
 * <mxCellEditor>. Default is true.
 */
mxGraph.prototype.invokesStopCellEditing = true;

/**
 * Variable: enterStopsCellEditing
 * 
 * If true, pressing the enter key without pressing control or shift will stop
 * editing and accept the new value. This is used in <mxCellEditor> to stop
 * cell editing. Note: You can always use F2 and escape to stop editing.
 * Default is false.
 */
mxGraph.prototype.enterStopsCellEditing = false;

/**
 * Variable: useScrollbarsForPanning
 * 
 * Specifies if scrollbars should be used for panning in <panGraph> if
 * any scrollbars are available. If scrollbars are enabled in CSS, but no
 * scrollbars appear because the graph is smaller than the container size,
 * then no panning occurs if this is true. Default is true.
 */
mxGraph.prototype.useScrollbarsForPanning = true;

/**
 * Variable: exportEnabled
 * 
 * Specifies the return value for <canExportCell>. Default is true.
 */
mxGraph.prototype.exportEnabled = true;

/**
 * Variable: importEnabled
 * 
 * Specifies the return value for <canImportCell>. Default is true.
 */
mxGraph.prototype.importEnabled = true;

/**
 * Variable: cellsLocked
 * 
 * Specifies the return value for <isCellLocked>. Default is false.
 */
mxGraph.prototype.cellsLocked = false;

/**
 * Variable: cellsCloneable
 * 
 * Specifies the return value for <isCellCloneable>. Default is true.
 */
mxGraph.prototype.cellsCloneable = true;

/**
 * Variable: foldingEnabled
 * 
 * Specifies if folding (collapse and expand via an image icon in the graph
 * should be enabled). Default is true.
 */
mxGraph.prototype.foldingEnabled = true;

/**
 * Variable: cellsEditable
 * 
 * Specifies the return value for <isCellEditable>. Default is true.
 */
mxGraph.prototype.cellsEditable = true;
\t\t
/**
 * Variable: cellsDeletable
 * 
 * Specifies the return value for <isCellDeletable>. Default is true.
 */
mxGraph.prototype.cellsDeletable = true;

/**
 * Variable: cellsMovable
 * 
 * Specifies the return value for <isCellMovable>. Default is true.
 */
mxGraph.prototype.cellsMovable = true;
\t
/**
 * Variable: edgeLabelsMovable
 * 
 * Specifies the return value for edges in <isLabelMovable>. Default is true.
 */
mxGraph.prototype.edgeLabelsMovable = true;
\t
/**
 * Variable: vertexLabelsMovable
 * 
 * Specifies the return value for vertices in <isLabelMovable>. Default is false.
 */
mxGraph.prototype.vertexLabelsMovable = false;

/**
 * Variable: dropEnabled
 * 
 * Specifies the return value for <isDropEnabled>. Default is false.
 */
mxGraph.prototype.dropEnabled = false;

/**
 * Variable: splitEnabled
 * 
 * Specifies if dropping onto edges should be enabled. This is ignored if
 * <dropEnabled> is false. If enabled, it will call <splitEdge> to carry
 * out the drop operation. Default is true.
 */
mxGraph.prototype.splitEnabled = true;

/**
 * Variable: cellsResizable
 * 
 * Specifies the return value for <isCellResizable>. Default is true.
 */
mxGraph.prototype.cellsResizable = true;

/**
 * Variable: cellsBendable
 * 
 * Specifies the return value for <isCellsBendable>. Default is true.
 */
mxGraph.prototype.cellsBendable = true;

/**
 * Variable: cellsSelectable
 * 
 * Specifies the return value for <isCellSelectable>. Default is true.
 */
mxGraph.prototype.cellsSelectable = true;

/**
 * Variable: cellsDisconnectable
 * 
 * Specifies the return value for <isCellDisconntable>. Default is true.
 */
mxGraph.prototype.cellsDisconnectable = true;

/**
 * Variable: autoSizeCells
 * 
 * Specifies if the graph should automatically update the cell size after an
 * edit. This is used in <isAutoSizeCell>. Default is false.
 */
mxGraph.prototype.autoSizeCells = false;

/**
 * Variable: autoSizeCellsOnAdd
 * 
 * Specifies if autoSize style should be applied when cells are added. Default is false.
 */
mxGraph.prototype.autoSizeCellsOnAdd = false;

/**
 * Variable: autoScroll
 * 
 * Specifies if the graph should automatically scroll if the mouse goes near
 * the container edge while dragging. This is only taken into account if the
 * container has scrollbars. Default is true.
 * 
 * If you need this to work without scrollbars then set <ignoreScrollbars> to
 * true. Please consult the <ignoreScrollbars> for details. In general, with
 * no scrollbars, the use of <allowAutoPanning> is recommended.
 */
mxGraph.prototype.autoScroll = true;

/**
 * Variable: ignoreScrollbars
 * 
 * Specifies if the graph should automatically scroll regardless of the
 * scrollbars. This will scroll the container using positive values for
 * scroll positions (ie usually only rightwards and downwards). To avoid
 * possible conflicts with panning, set <translateToScrollPosition> to true.
 */
mxGraph.prototype.ignoreScrollbars = false;

/**
 * Variable: translateToScrollPosition
 * 
 * Specifies if the graph should automatically convert the current scroll
 * position to a translate in the graph view when a mouseUp event is received.
 * This can be used to avoid conflicts when using <autoScroll> and
 * <ignoreScrollbars> with no scrollbars in the container.
 */
mxGraph.prototype.translateToScrollPosition = false;

/**
 * Variable: timerAutoScroll
 * 
 * Specifies if autoscrolling should be carried out via mxPanningManager even
 * if the container has scrollbars. This disables <scrollPointToVisible> and
 * uses <mxPanningManager> instead. If this is true then <autoExtend> is
 * disabled. It should only be used with a scroll buffer or when scollbars
 * are visible and scrollable in all directions. Default is false.
 */
mxGraph.prototype.timerAutoScroll = false;

/**
 * Variable: allowAutoPanning
 * 
 * Specifies if panning via <panGraph> should be allowed to implement autoscroll
 * if no scrollbars are available in <scrollPointToVisible>. To enable panning
 * inside the container, near the edge, set <mxPanningManager.border> to a
 * positive value. Default is false.
 */
mxGraph.prototype.allowAutoPanning = false;

/**
 * Variable: autoExtend
 * 
 * Specifies if the size of the graph should be automatically extended if the
 * mouse goes near the container edge while dragging. This is only taken into
 * account if the container has scrollbars. Default is true. See <autoScroll>.
 */
mxGraph.prototype.autoExtend = true;

/**
 * Variable: maximumGraphBounds
 * 
 * <mxRectangle> that specifies the area in which all cells in the diagram
 * should be placed. Uses in <getMaximumGraphBounds>. Use a width or height of
 * 0 if you only want to give a upper, left corner.
 */
mxGraph.prototype.maximumGraphBounds = null;

/**
 * Variable: minimumGraphSize
 * 
 * <mxRectangle> that specifies the minimum size of the graph. This is ignored
 * if the graph container has no scrollbars. Default is null.
 */
mxGraph.prototype.minimumGraphSize = null;

/**
 * Variable: minimumContainerSize
 * 
 * <mxRectangle> that specifies the minimum size of the <container> if
 * <resizeContainer> is true.
 */
mxGraph.prototype.minimumContainerSize = null;
\t\t
/**
 * Variable: maximumContainerSize
 * 
 * <mxRectangle> that specifies the maximum size of the container if
 * <resizeContainer> is true.
 */
mxGraph.prototype.maximumContainerSize = null;

/**
 * Variable: resizeContainer
 * 
 * Specifies if the container should be resized to the graph size when
 * the graph size has changed. Default is false.
 */
mxGraph.prototype.resizeContainer = false;

/**
 * Variable: border
 * 
 * Border to be added to the bottom and right side when the container is
 * being resized after the graph has been changed. Default is 0.
 */
mxGraph.prototype.border = 0;
\t\t
/**
 * Variable: keepEdgesInForeground
 * 
 * Specifies if edges should appear in the foreground regardless of their order
 * in the model. If <keepEdgesInForeground> and <keepEdgesInBackground> are
 * both true then the normal order is applied. Default is false.
 */
mxGraph.prototype.keepEdgesInForeground = false;

/**
 * Variable: keepEdgesInBackground
 * 
 * Specifies if edges should appear in the background regardless of their order
 * in the model. If <keepEdgesInForeground> and <keepEdgesInBackground> are
 * both true then the normal order is applied. Default is false.
 */
mxGraph.prototype.keepEdgesInBackground = false;

/**
 * Variable: allowNegativeCoordinates
 * 
 * Specifies if negative coordinates for vertices are allowed. Default is true.
 */
mxGraph.prototype.allowNegativeCoordinates = true;

/**
 * Variable: constrainChildren
 * 
 * Specifies if a child should be constrained inside the parent bounds after a
 * move or resize of the child. Default is true.
 */
mxGraph.prototype.constrainChildren = true;

/**
 * Variable: constrainRelativeChildren
 * 
 * Specifies if child cells with relative geometries should be constrained
 * inside the parent bounds, if <constrainChildren> is true, and/or the
 * <maximumGraphBounds>. Default is false.
 */
mxGraph.prototype.constrainRelativeChildren = false;

/**
 * Variable: extendParents
 * 
 * Specifies if a parent should contain the child bounds after a resize of
 * the child. Default is true. This has precedence over <constrainChildren>.
 */
mxGraph.prototype.extendParents = true;

/**
 * Variable: extendParentsOnAdd
 * 
 * Specifies if parents should be extended according to the <extendParents>
 * switch if cells are added. Default is true.
 */
mxGraph.prototype.extendParentsOnAdd = true;

/**
 * Variable: extendParentsOnAdd
 * 
 * Specifies if parents should be extended according to the <extendParents>
 * switch if cells are added. Default is false for backwards compatiblity.
 */
mxGraph.prototype.extendParentsOnMove = false;

/**
 * Variable: recursiveResize
 * 
 * Specifies the return value for <isRecursiveResize>. Default is
 * false for backwards compatiblity.
 */
mxGraph.prototype.recursiveResize = false;

/**
 * Variable: collapseToPreferredSize
 * 
 * Specifies if the cell size should be changed to the preferred size when
 * a cell is first collapsed. Default is true.
 */
mxGraph.prototype.collapseToPreferredSize = true;

/**
 * Variable: zoomFactor
 * 
 * Specifies the factor used for <zoomIn> and <zoomOut>. Default is 1.2
 * (120%).
 */
mxGraph.prototype.zoomFactor = 1.2;

/**
 * Variable: keepSelectionVisibleOnZoom
 * 
 * Specifies if the viewport should automatically contain the selection cells
 * after a zoom operation. Default is false.
 */
mxGraph.prototype.keepSelectionVisibleOnZoom = false;

/**
 * Variable: centerZoom
 * 
 * Specifies if the zoom operations should go into the center of the actual
 * diagram rather than going from top, left. Default is true.
 */
mxGraph.prototype.centerZoom = true;

/**
 * Variable: resetViewOnRootChange
 * 
 * Specifies if the scale and translate should be reset if the root changes in
 * the model. Default is true.
 */
mxGraph.prototype.resetViewOnRootChange = true;

/**
 * Variable: resetEdgesOnResize
 * 
 * Specifies if edge control points should be reset after the resize of a
 * connected cell. Default is false.
 */
mxGraph.prototype.resetEdgesOnResize = false;

/**
 * Variable: resetEdgesOnMove
 * 
 * Specifies if edge control points should be reset after the move of a
 * connected cell. Default is false.
 */
mxGraph.prototype.resetEdgesOnMove = false;

/**
 * Variable: resetEdgesOnConnect
 * 
 * Specifies if edge control points should be reset after the the edge has been
 * reconnected. Default is true.
 */
mxGraph.prototype.resetEdgesOnConnect = true;

/**
 * Variable: allowLoops
 * 
 * Specifies if loops (aka self-references) are allowed. Default is false.
 */
mxGraph.prototype.allowLoops = false;
\t
/**
 * Variable: defaultLoopStyle
 * 
 * <mxEdgeStyle> to be used for loops. This is a fallback for loops if the
 * <mxConstants.STYLE_LOOP> is undefined. Default is <mxEdgeStyle.Loop>.
 */
mxGraph.prototype.defaultLoopStyle = mxEdgeStyle.Loop;

/**
 * Variable: multigraph
 * 
 * Specifies if multiple edges in the same direction between the same pair of
 * vertices are allowed. Default is true.
 */
mxGraph.prototype.multigraph = true;

/**
 * Variable: connectableEdges
 * 
 * Specifies if edges are connectable. Default is false. This overrides the
 * connectable field in edges.
 */
mxGraph.prototype.connectableEdges = false;

/**
 * Variable: allowDanglingEdges
 * 
 * Specifies if edges with disconnected terminals are allowed in the graph.
 * Default is true.
 */
mxGraph.prototype.allowDanglingEdges = true;

/**
 * Variable: cloneInvalidEdges
 * 
 * Specifies if edges that are cloned should be validated and only inserted
 * if they are valid. Default is true.
 */
mxGraph.prototype.cloneInvalidEdges = false;

/**
 * Variable: disconnectOnMove
 * 
 * Specifies if edges should be disconnected from their terminals when they
 * are moved. Default is true.
 */
mxGraph.prototype.disconnectOnMove = true;

/**
 * Variable: labelsVisible
 * 
 * Specifies if labels should be visible. This is used in <getLabel>. Default
 * is true.
 */
mxGraph.prototype.labelsVisible = true;
\t
/**
 * Variable: htmlLabels
 * 
 * Specifies the return value for <isHtmlLabel>. Default is false.
 */
mxGraph.prototype.htmlLabels = false;

/**
 * Variable: swimlaneSelectionEnabled
 * 
 * Specifies if swimlanes should be selectable via the content if the
 * mouse is released. Default is true.
 */
mxGraph.prototype.swimlaneSelectionEnabled = true;

/**
 * Variable: swimlaneNesting
 * 
 * Specifies if nesting of swimlanes is allowed. Default is true.
 */
mxGraph.prototype.swimlaneNesting = true;
\t
/**
 * Variable: swimlaneIndicatorColorAttribute
 * 
 * The attribute used to find the color for the indicator if the indicator
 * color is set to 'swimlane'. Default is <mxConstants.STYLE_FILLCOLOR>.
 */
mxGraph.prototype.swimlaneIndicatorColorAttribute = mxConstants.STYLE_FILLCOLOR;

/**
 * Variable: imageBundles
 * 
 * Holds the list of image bundles.
 */
mxGraph.prototype.imageBundles = null;

/**
 * Variable: minFitScale
 * 
 * Specifies the minimum scale to be applied in <fit>. Default is 0.1. Set this
 * to null to allow any value.
 */
mxGraph.prototype.minFitScale = 0.1;

/**
 * Variable: maxFitScale
 * 
 * Specifies the maximum scale to be applied in <fit>. Default is 8. Set this
 * to null to allow any value.
 */
mxGraph.prototype.maxFitScale = 8;

/**
 * Variable: panDx
 * 
 * Current horizontal panning value. Default is 0.
 */
mxGraph.prototype.panDx = 0;

/**
 * Variable: panDy
 * 
 * Current vertical panning value. Default is 0.
 */
mxGraph.prototype.panDy = 0;

/**
 * Variable: collapsedImage
 * 
 * Specifies the <mxImage> to indicate a collapsed state.
 * Default value is mxClient.imageBasePath + '/collapsed.gif'
 */
mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9);

/**
 * Variable: expandedImage
 * 
 * Specifies the <mxImage> to indicate a expanded state.
 * Default value is mxClient.imageBasePath + '/expanded.gif'
 */
mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9);

/**
 * Variable: warningImage
 * 
 * Specifies the <mxImage> for the image to be used to display a warning
 * overlay. See <setCellWarning>. Default value is mxClient.imageBasePath +
 * '/warning'.  The extension for the image depends on the platform. It is
 * '.png' on the Mac and '.gif' on all other platforms.
 */
mxGraph.prototype.warningImage = new mxImage(mxClient.imageBasePath + '/warning'+
\t((mxClient.IS_MAC) ? '.png' : '.gif'), 16, 16);

/**
 * Variable: alreadyConnectedResource
 * 
 * Specifies the resource key for the error message to be displayed in
 * non-multigraphs when two vertices are already connected. If the resource
 * for this key does not exist then the value is used as the error message.
 * Default is 'alreadyConnected'.
 */
mxGraph.prototype.alreadyConnectedResource = (mxClient.language != 'none') ? 'alreadyConnected' : '';

/**
 * Variable: containsValidationErrorsResource
 * 
 * Specifies the resource key for the warning message to be displayed when
 * a collapsed cell contains validation errors. If the resource for this
 * key does not exist then the value is used as the warning message.
 * Default is 'containsValidationErrors'.
 */
mxGraph.prototype.containsValidationErrorsResource = (mxClient.language != 'none') ? 'containsValidationErrors' : '';

/**
 * Variable: collapseExpandResource
 * 
 * Specifies the resource key for the tooltip on the collapse/expand icon.
 * If the resource for this key does not exist then the value is used as
 * the tooltip. Default is 'collapse-expand'.
 */
mxGraph.prototype.collapseExpandResource = (mxClient.language != 'none') ? 'collapse-expand' : '';

/**
 * Function: init
 * 
 * Initializes the <container> and creates the respective datastructures.
 * 
 * Parameters:
 * 
 * container - DOM node that will contain the graph display.
 */
mxGraph.prototype.init = function(container)
{
\tthis.container = container;
\t
\t// Initializes the in-place editor
\tthis.cellEditor = this.createCellEditor();\t

\t// Initializes the container using the view
\tthis.view.init();
\t
\t// Updates the size of the container for the current graph
\tthis.sizeDidChange();
\t
\t// Hides tooltips and resets tooltip timer if mouse leaves container
\tmxEvent.addListener(container, 'mouseleave', mxUtils.bind(this, function(evt)
\t{
\t\tif (this.tooltipHandler != null && this.tooltipHandler.div != null &&
\t\t\tthis.tooltipHandler.div != evt.relatedTarget)
\t\t{
\t\t\tthis.tooltipHandler.hide();
\t\t}
\t}));

\t// Automatic deallocation of memory
\tif (mxClient.IS_IE)
\t{
\t\tmxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
\t\t{
\t\t\tthis.destroy();
\t\t}));
\t\t
\t\t// Disable shift-click for text
\t\tmxEvent.addListener(container, 'selectstart',
\t\t\tmxUtils.bind(this, function(evt)
\t\t\t{
\t\t\t\treturn this.isEditing() || (!this.isMouseDown && !mxEvent.isShiftDown(evt));
\t\t\t})
\t\t);
\t}
\t
\t// Workaround for missing last shape and connect preview in IE8 standards
\t// mode if no initial graph displayed or no label for shape defined
\tif (document.documentMode == 8)
\t{
\t\tcontainer.insertAdjacentHTML('beforeend', '<' + mxClient.VML_PREFIX + ':group' +
\t\t\t' style=\"DISPLAY: none;\"></' + mxClient.VML_PREFIX + ':group>');
\t}
};

/**
 * Function: createHandlers
 * 
 * Creates the tooltip-, panning-, connection- and graph-handler (in this
 * order). This is called in the constructor before <init> is called.
 */
mxGraph.prototype.createHandlers = function()
{
\tthis.tooltipHandler = this.createTooltipHandler();
\tthis.tooltipHandler.setEnabled(false);
\tthis.selectionCellsHandler = this.createSelectionCellsHandler();
\tthis.connectionHandler = this.createConnectionHandler();
\tthis.connectionHandler.setEnabled(false);
\tthis.graphHandler = this.createGraphHandler();
\tthis.panningHandler = this.createPanningHandler();
\tthis.panningHandler.panningEnabled = false;
\tthis.popupMenuHandler = this.createPopupMenuHandler();
};

/**
 * Function: createTooltipHandler
 * 
 * Creates and returns a new <mxTooltipHandler> to be used in this graph.
 */
mxGraph.prototype.createTooltipHandler = function()
{
\treturn new mxTooltipHandler(this);
};

/**
 * Function: createSelectionCellsHandler
 * 
 * Creates and returns a new <mxTooltipHandler> to be used in this graph.
 */
mxGraph.prototype.createSelectionCellsHandler = function()
{
\treturn new mxSelectionCellsHandler(this);
};

/**
 * Function: createConnectionHandler
 * 
 * Creates and returns a new <mxConnectionHandler> to be used in this graph.
 */
mxGraph.prototype.createConnectionHandler = function()
{
\treturn new mxConnectionHandler(this);
};

/**
 * Function: createGraphHandler
 * 
 * Creates and returns a new <mxGraphHandler> to be used in this graph.
 */
mxGraph.prototype.createGraphHandler = function()
{
\treturn new mxGraphHandler(this);
};

/**
 * Function: createPanningHandler
 * 
 * Creates and returns a new <mxPanningHandler> to be used in this graph.
 */
mxGraph.prototype.createPanningHandler = function()
{
\treturn new mxPanningHandler(this);
};

/**
 * Function: createPopupMenuHandler
 * 
 * Creates and returns a new <mxPopupMenuHandler> to be used in this graph.
 */
mxGraph.prototype.createPopupMenuHandler = function()
{
\treturn new mxPopupMenuHandler(this);
};

/**
 * Function: createSelectionModel
 * 
 * Creates a new <mxGraphSelectionModel> to be used in this graph.
 */
mxGraph.prototype.createSelectionModel = function()
{
\treturn new mxGraphSelectionModel(this);
};

/**
 * Function: createStylesheet
 * 
 * Creates a new <mxGraphSelectionModel> to be used in this graph.
 */
mxGraph.prototype.createStylesheet = function()
{
\treturn new mxStylesheet();
};

/**
 * Function: createGraphView
 * 
 * Creates a new <mxGraphView> to be used in this graph.
 */
mxGraph.prototype.createGraphView = function()
{
\treturn new mxGraphView(this);
};
 
/**
 * Function: createCellRenderer
 * 
 * Creates a new <mxCellRenderer> to be used in this graph.
 */
mxGraph.prototype.createCellRenderer = function()
{
\treturn new mxCellRenderer();
};

/**
 * Function: createCellEditor
 * 
 * Creates a new <mxCellEditor> to be used in this graph.
 */
mxGraph.prototype.createCellEditor = function()
{
\treturn new mxCellEditor(this);
};

/**
 * Function: getModel
 * 
 * Returns the <mxGraphModel> that contains the cells.
 */
mxGraph.prototype.getModel = function()
{
\treturn this.model;
};

/**
 * Function: getView
 * 
 * Returns the <mxGraphView> that contains the <mxCellStates>.
 */
mxGraph.prototype.getView = function()
{
\treturn this.view;
};

/**
 * Function: getStylesheet
 * 
 * Returns the <mxStylesheet> that defines the style.
 */
mxGraph.prototype.getStylesheet = function()
{
\treturn this.stylesheet;
};

/**
 * Function: setStylesheet
 * 
 * Sets the <mxStylesheet> that defines the style.
 */
mxGraph.prototype.setStylesheet = function(stylesheet)
{
\tthis.stylesheet = stylesheet;
};

/**
 * Function: getSelectionModel
 * 
 * Returns the <mxGraphSelectionModel> that contains the selection.
 */
mxGraph.prototype.getSelectionModel = function()
{
\treturn this.selectionModel;
};

/**
 * Function: setSelectionModel
 * 
 * Sets the <mxSelectionModel> that contains the selection.
 */
mxGraph.prototype.setSelectionModel = function(selectionModel)
{
\tthis.selectionModel = selectionModel;
};

/**
 * Function: getSelectionCellsForChanges
 * 
 * Returns the cells to be selected for the given array of changes.
 * 
 * Parameters:
 * 
 * ignoreFn - Optional function that takes a change and returns true if the
 * change should be ignored.
 * 
 */
mxGraph.prototype.getSelectionCellsForChanges = function(changes, ignoreFn)
{
\tvar dict = new mxDictionary();
\tvar cells = [];
\t
\tvar addCell = mxUtils.bind(this, function(cell)
\t{
\t\tif (!dict.get(cell) && this.model.contains(cell))
\t\t{
\t\t\tif (this.model.isEdge(cell) || this.model.isVertex(cell))
\t\t\t{
\t\t\t\tdict.put(cell, true);
\t\t\t\tcells.push(cell);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar childCount = this.model.getChildCount(cell);
\t\t\t\t
\t\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t\t{
\t\t\t\t\taddCell(this.model.getChildAt(cell, i));
\t\t\t\t}
\t\t\t}
\t\t}
\t});

\tfor (var i = 0; i < changes.length; i++)
\t{
\t\tvar change = changes[i];
\t\t
\t\tif (change.constructor != mxRootChange &&
\t\t\t(ignoreFn == null || !ignoreFn(change)))
\t\t{
\t\t\tvar cell = null;

\t\t\tif (change instanceof mxChildChange)
\t\t\t{
\t\t\t\tcell = change.child;
\t\t\t}
\t\t\telse if (change.cell != null &&
\t\t\t\tchange.cell instanceof mxCell)
\t\t\t{
\t\t\t\tcell = change.cell;
\t\t\t}
\t\t\t
\t\t\tif (cell != null)
\t\t\t{
\t\t\t\taddCell(cell);
\t\t\t}
\t\t}
\t}
\t
\treturn cells;
};

/**
 * Function: graphModelChanged
 * 
 * Called when the graph model changes. Invokes <processChange> on each
 * item of the given array to update the view accordingly.
 * 
 * Parameters:
 * 
 * changes - Array that contains the individual changes.
 */
mxGraph.prototype.graphModelChanged = function(changes)
{
\tfor (var i = 0; i < changes.length; i++)
\t{
\t\tthis.processChange(changes[i]);
\t}

\tthis.updateSelection();
\tthis.view.validate();
\tthis.sizeDidChange();
};

/**
 * Function: updateSelection
 * 
 * Removes selection cells that are not in the model from the selection.
 */
mxGraph.prototype.updateSelection = function()
{
\tvar cells = this.getSelectionCells();
\tvar removed = [];
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tif (!this.model.contains(cells[i]) || !this.isCellVisible(cells[i]))
\t\t{
\t\t\tremoved.push(cells[i]);
\t\t}
\t\telse
\t\t{
\t\t\tvar par = this.model.getParent(cells[i]);
\t\t\t
\t\t\twhile (par != null && par != this.view.currentRoot)
\t\t\t{
\t\t\t\tif (this.isCellCollapsed(par) || !this.isCellVisible(par))
\t\t\t\t{
\t\t\t\t\tremoved.push(cells[i]);
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t\t
\t\t\t\tpar = this.model.getParent(par);
\t\t\t}
\t\t}
\t}
\t
\tthis.removeSelectionCells(removed);
};

/**
 * Function: processChange
 * 
 * Processes the given change and invalidates the respective cached data
 * in <view>. This fires a <root> event if the root has changed in the
 * model.
 * 
 * Parameters:
 * 
 * change - Object that represents the change on the model.
 */
mxGraph.prototype.processChange = function(change)
{
\t// Resets the view settings, removes all cells and clears
\t// the selection if the root changes.
\tif (change instanceof mxRootChange)
\t{
\t\tthis.clearSelection();
\t\tthis.setDefaultParent(null);
\t\tthis.removeStateForCell(change.previous);
\t\t
\t\tif (this.resetViewOnRootChange)
\t\t{
\t\t\tthis.view.scale = 1;
\t\t\tthis.view.translate.x = 0;
\t\t\tthis.view.translate.y = 0;
\t\t}

\t\tthis.fireEvent(new mxEventObject(mxEvent.ROOT));
\t}
\t
\t// Adds or removes a child to the view by online invaliding
\t// the minimal required portions of the cache, namely, the
\t// old and new parent and the child.
\telse if (change instanceof mxChildChange)
\t{
\t\tvar newParent = this.model.getParent(change.child);
\t\tthis.view.invalidate(change.child, true, true);
\t\t
\t\tif (!this.model.contains(newParent) || this.isCellCollapsed(newParent))
\t\t{
\t\t\tthis.view.invalidate(change.child, true, true);
\t\t\tthis.removeStateForCell(change.child);
\t\t\t
\t\t\t// Handles special case of current root of view being removed
\t\t\tif (this.view.currentRoot == change.child)
\t\t\t{
\t\t\t\tthis.home();
\t\t\t}
\t\t}
 
\t\tif (newParent != change.previous)
\t\t{
\t\t\t// Refreshes the collapse/expand icons on the parents
\t\t\tif (newParent != null)
\t\t\t{
\t\t\t\tthis.view.invalidate(newParent, false, false);
\t\t\t}
\t\t\t
\t\t\tif (change.previous != null)
\t\t\t{
\t\t\t\tthis.view.invalidate(change.previous, false, false);
\t\t\t}
\t\t}
\t}

\t// Handles two special cases where the shape does not need to be
\t// recreated from scratch, it only needs to be invalidated.
\telse if (change instanceof mxTerminalChange || change instanceof mxGeometryChange)
\t{
\t\t// Checks if the geometry has changed to avoid unnessecary revalidation
\t\tif (change instanceof mxTerminalChange || ((change.previous == null && change.geometry != null) ||
\t\t\t(change.previous != null && !change.previous.equals(change.geometry))))
\t\t{
\t\t\tthis.view.invalidate(change.cell);
\t\t}
\t}

\t// Handles two special cases where only the shape, but no
\t// descendants need to be recreated
\telse if (change instanceof mxValueChange)
\t{
\t\tthis.view.invalidate(change.cell, false, false);
\t}
\t
\t// Requires a new mxShape in JavaScript
\telse if (change instanceof mxStyleChange)
\t{
\t\tthis.view.invalidate(change.cell, true, true);
\t\tvar state = this.view.getState(change.cell);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tstate.invalidStyle = true;
\t\t}
\t}
\t
\t// Removes the state from the cache by default
\telse if (change.cell != null && change.cell instanceof mxCell)
\t{
\t\tthis.removeStateForCell(change.cell);
\t}
};

/**
 * Function: removeStateForCell
 * 
 * Removes all cached information for the given cell and its descendants.
 * This is called when a cell was removed from the model.
 * 
 * Paramters:
 * 
 * cell - <mxCell> that was removed from the model.
 */
mxGraph.prototype.removeStateForCell = function(cell)
{
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tthis.removeStateForCell(this.model.getChildAt(cell, i));
\t}

\tthis.view.invalidate(cell, false, true);
\tthis.view.removeState(cell);
};

/**
 * Group: Overlays
 */

/**
 * Function: addCellOverlay
 * 
 * Adds an <mxCellOverlay> for the specified cell. This method fires an
 * <addoverlay> event and returns the new <mxCellOverlay>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to add the overlay for.
 * overlay - <mxCellOverlay> to be added for the cell.
 */
mxGraph.prototype.addCellOverlay = function(cell, overlay)
{
\tif (cell.overlays == null)
\t{
\t\tcell.overlays = [];
\t}
\t
\tcell.overlays.push(overlay);

\tvar state = this.view.getState(cell);

\t// Immediately updates the cell display if the state exists
\tif (state != null)
\t{
\t\tthis.cellRenderer.redraw(state);
\t}
\t
\tthis.fireEvent(new mxEventObject(mxEvent.ADD_OVERLAY,
\t\t\t'cell', cell, 'overlay', overlay));
\t
\treturn overlay;
};

/**
 * Function: getCellOverlays
 * 
 * Returns the array of <mxCellOverlays> for the given cell or null, if
 * no overlays are defined.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose overlays should be returned.
 */
mxGraph.prototype.getCellOverlays = function(cell)
{
\treturn cell.overlays;
};

/**
 * Function: removeCellOverlay
 * 
 * Removes and returns the given <mxCellOverlay> from the given cell. This
 * method fires a <removeoverlay> event. If no overlay is given, then all
 * overlays are removed using <removeOverlays>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose overlay should be removed.
 * overlay - Optional <mxCellOverlay> to be removed.
 */
mxGraph.prototype.removeCellOverlay = function(cell, overlay)
{
\tif (overlay == null)
\t{
\t\tthis.removeCellOverlays(cell);
\t}
\telse
\t{
\t\tvar index = mxUtils.indexOf(cell.overlays, overlay);
\t\t
\t\tif (index >= 0)
\t\t{
\t\t\tcell.overlays.splice(index, 1);
\t\t\t
\t\t\tif (cell.overlays.length == 0)
\t\t\t{
\t\t\t\tcell.overlays = null;
\t\t\t}
\t\t\t
\t\t\t// Immediately updates the cell display if the state exists
\t\t\tvar state = this.view.getState(cell);
\t\t\t
\t\t\tif (state != null)
\t\t\t{
\t\t\t\tthis.cellRenderer.redraw(state);
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
\t\t\t\t\t'cell', cell, 'overlay', overlay));\t
\t\t}
\t\telse
\t\t{
\t\t\toverlay = null;
\t\t}
\t}
\t
\treturn overlay;
};

/**
 * Function: removeCellOverlays
 * 
 * Removes all <mxCellOverlays> from the given cell. This method
 * fires a <removeoverlay> event for each <mxCellOverlay> and returns
 * the array of <mxCellOverlays> that was removed from the cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose overlays should be removed
 */
mxGraph.prototype.removeCellOverlays = function(cell)
{
\tvar overlays = cell.overlays;
\t
\tif (overlays != null)
\t{
\t\tcell.overlays = null;
\t\t
\t\t// Immediately updates the cell display if the state exists
\t\tvar state = this.view.getState(cell);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tthis.cellRenderer.redraw(state);
\t\t}
\t\t
\t\tfor (var i = 0; i < overlays.length; i++)
\t\t{
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
\t\t\t\t\t'cell', cell, 'overlay', overlays[i]));
\t\t}
\t}
\t
\treturn overlays;
};

/**
 * Function: clearCellOverlays
 * 
 * Removes all <mxCellOverlays> in the graph for the given cell and all its
 * descendants. If no cell is specified then all overlays are removed from
 * the graph. This implementation uses <removeCellOverlays> to remove the
 * overlays from the individual cells.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> that represents the root of the subtree to
 * remove the overlays from. Default is the root in the model.
 */
mxGraph.prototype.clearCellOverlays = function(cell)
{
\tcell = (cell != null) ? cell : this.model.getRoot();
\tthis.removeCellOverlays(cell);
\t
\t// Recursively removes all overlays from the children
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = this.model.getChildAt(cell, i);
\t\tthis.clearCellOverlays(child); // recurse
\t}
};

/**
 * Function: setCellWarning
 * 
 * Creates an overlay for the given cell using the warning and image or
 * <warningImage> and returns the new <mxCellOverlay>. The warning is
 * displayed as a tooltip in a red font and may contain HTML markup. If
 * the warning is null or a zero length string, then all overlays are
 * removed from the cell.
 * 
 * Example:
 * 
 * (code)
 * graph.setCellWarning(cell, '<b>Warning:</b>: Hello, World!');
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose warning should be set.
 * warning - String that represents the warning to be displayed.
 * img - Optional <mxImage> to be used for the overlay. Default is
 * <warningImage>.
 * isSelect - Optional boolean indicating if a click on the overlay
 * should select the corresponding cell. Default is false.
 */
mxGraph.prototype.setCellWarning = function(cell, warning, img, isSelect)
{
\tif (warning != null && warning.length > 0)
\t{
\t\timg = (img != null) ? img : this.warningImage;
\t\t
\t\t// Creates the overlay with the image and warning
\t\tvar overlay = new mxCellOverlay(img,
\t\t\t'<font color=red>'+warning+'</font>');
\t\t
\t\t// Adds a handler for single mouseclicks to select the cell
\t\tif (isSelect)
\t\t{
\t\t\toverlay.addListener(mxEvent.CLICK,
\t\t\t\tmxUtils.bind(this, function(sender, evt)
\t\t\t\t{
\t\t\t\t\tif (this.isEnabled())
\t\t\t\t\t{
\t\t\t\t\t\tthis.setSelectionCell(cell);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t);
\t\t}
\t\t
\t\t// Sets and returns the overlay in the graph
\t\treturn this.addCellOverlay(cell, overlay);
\t}
\telse
\t{
\t\tthis.removeCellOverlays(cell);
\t}
\t
\treturn null;
};

/**
 * Group: In-place editing
 */

/**
 * Function: startEditing
 * 
 * Calls <startEditingAtCell> using the given cell or the first selection
 * cell.
 * 
 * Parameters:
 * 
 * evt - Optional mouse event that triggered the editing.
 */
mxGraph.prototype.startEditing = function(evt)
{
\tthis.startEditingAtCell(null, evt);
};

/**
 * Function: startEditingAtCell
 * 
 * Fires a <startEditing> event and invokes <mxCellEditor.startEditing>
 * on <editor>. After editing was started, a <editingStarted> event is
 * fired.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to start the in-place editor for.
 * evt - Optional mouse event that triggered the editing.
 */
mxGraph.prototype.startEditingAtCell = function(cell, evt)
{
\tif (evt == null || !mxEvent.isMultiTouchEvent(evt))
\t{
\t\tif (cell == null)
\t\t{
\t\t\tcell = this.getSelectionCell();
\t\t\t
\t\t\tif (cell != null && !this.isCellEditable(cell))
\t\t\t{
\t\t\t\tcell = null;
\t\t\t}
\t\t}
\t
\t\tif (cell != null)
\t\t{
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.START_EDITING,
\t\t\t\t\t'cell', cell, 'event', evt));
\t\t\tthis.cellEditor.startEditing(cell, evt);
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.EDITING_STARTED,
\t\t\t\t\t'cell', cell, 'event', evt));
\t\t}
\t}
};

/**
 * Function: getEditingValue
 * 
 * Returns the initial value for in-place editing. This implementation
 * returns <convertValueToString> for the given cell. If this function is
 * overridden, then <mxGraphModel.valueForCellChanged> should take care
 * of correctly storing the actual new value inside the user object.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the initial editing value should be returned.
 * evt - Optional mouse event that triggered the editor.
 */
mxGraph.prototype.getEditingValue = function(cell, evt)
{
\treturn this.convertValueToString(cell);
};

/**
 * Function: stopEditing
 * 
 * Stops the current editing  and fires a <editingStopped> event.
 * 
 * Parameters:
 * 
 * cancel - Boolean that specifies if the current editing value
 * should be stored.
 */
mxGraph.prototype.stopEditing = function(cancel)
{
\tthis.cellEditor.stopEditing(cancel);
\tthis.fireEvent(new mxEventObject(mxEvent.EDITING_STOPPED, 'cancel', cancel));
};

/**
 * Function: labelChanged
 * 
 * Sets the label of the specified cell to the given value using
 * <cellLabelChanged> and fires <mxEvent.LABEL_CHANGED> while the
 * transaction is in progress. Returns the cell whose label was changed.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose label should be changed.
 * value - New label to be assigned.
 * evt - Optional event that triggered the change.
 */
mxGraph.prototype.labelChanged = function(cell, value, evt)
{
\tthis.model.beginUpdate();
\ttry
\t{
\t\tvar old = cell.value;
\t\tthis.cellLabelChanged(cell, value, this.isAutoSizeCell(cell));
\t\tthis.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED,
\t\t\t'cell', cell, 'value', value, 'old', old, 'event', evt));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}
\t
\treturn cell;
};

/**
 * Function: cellLabelChanged
 * 
 * Sets the new label for a cell. If autoSize is true then
 * <cellSizeUpdated> will be called.
 * 
 * In the following example, the function is extended to map changes to
 * attributes in an XML node, as shown in <convertValueToString>.
 * Alternatively, the handling of this can be implemented as shown in
 * <mxGraphModel.valueForCellChanged> without the need to clone the
 * user object.
 * 
 * (code)
 * var graphCellLabelChanged = graph.cellLabelChanged;
 * graph.cellLabelChanged = function(cell, newValue, autoSize)
 * {
 * \t// Cloned for correct undo/redo
 * \tvar elt = cell.value.cloneNode(true);
 *  elt.setAttribute('label', newValue);
 *  
 *  newValue = elt;
 *  graphCellLabelChanged.apply(this, arguments);
 * };
 * (end) 
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose label should be changed.
 * value - New label to be assigned.
 * autoSize - Boolean that specifies if <cellSizeUpdated> should be called.
 */
mxGraph.prototype.cellLabelChanged = function(cell, value, autoSize)
{
\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.model.setValue(cell, value);
\t\t
\t\tif (autoSize)
\t\t{
\t\t\tthis.cellSizeUpdated(cell, false);
\t\t}
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}
};

/**
 * Group: Event processing
 */

/**
 * Function: escape
 * 
 * Processes an escape keystroke.
 * 
 * Parameters:
 * 
 * evt - Mouseevent that represents the keystroke.
 */
mxGraph.prototype.escape = function(evt)
{
\tthis.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt));
};

/**
 * Function: click
 * 
 * Processes a singleclick on an optional cell and fires a <click> event.
 * The click event is fired initially. If the graph is enabled and the
 * event has not been consumed, then the cell is selected using
 * <selectCellForEvent> or the selection is cleared using
 * <clearSelection>. The events consumed state is set to true if the
 * corresponding <mxMouseEvent> has been consumed.
 *
 * To handle a click event, use the following code.
 * 
 * (code)
 * graph.addListener(mxEvent.CLICK, function(sender, evt)
 * {
 *   var e = evt.getProperty('event'); // mouse event
 *   var cell = evt.getProperty('cell'); // cell may be null
 *   
 *   if (cell != null)
 *   {
 *     // Do something useful with cell and consume the event
 *     evt.consume();
 *   }
 * });
 * (end)
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> that represents the single click.
 */
mxGraph.prototype.click = function(me)
{
\tvar evt = me.getEvent();
\tvar cell = me.getCell();
\tvar mxe = new mxEventObject(mxEvent.CLICK, 'event', evt, 'cell', cell);
\t
\tif (me.isConsumed())
\t{
\t\tmxe.consume();
\t}
\t
\tthis.fireEvent(mxe);
\t
\tif (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed())
\t{
\t\tif (cell != null)
\t\t{
\t\t\tif (this.isTransparentClickEvent(evt))
\t\t\t{
\t\t\t\tvar active = false;
\t\t\t\t
\t\t\t\tvar tmp = this.getCellAt(me.graphX, me.graphY, null, null, null,
\t\t\t\t\tmxUtils.bind(this, function(state)
\t\t\t\t{
\t\t\t\t\tvar selected = this.isCellSelected(state.cell);
\t\t\t\t\tactive = active || selected;
\t\t\t\t\t
\t\t\t\t\treturn !active || selected || (state.cell != cell &&
\t\t\t\t\t\tthis.model.isAncestor(state.cell, cell));
\t\t\t\t}));
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\tcell = tmp;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (this.isSwimlaneSelectionEnabled())
\t\t{
\t\t\tcell = this.getSwimlaneAt(me.getGraphX(), me.getGraphY());
\t\t\t\t
\t\t\tif (cell != null && (!this.isToggleEvent(evt) ||
\t\t\t\t!mxEvent.isAltDown(evt)))
\t\t\t{
\t\t\t\tvar temp = cell;
\t\t\t\tvar swimlanes = [];
\t\t\t\t
\t\t\t\twhile (temp != null)
\t\t\t\t{
\t\t\t\t\ttemp = this.model.getParent(temp);
\t\t\t\t\tvar state = this.view.getState(temp);
\t\t\t\t\t
\t\t\t\t\tif (this.isSwimlane(temp) && state != null)
\t\t\t\t\t{
\t\t\t\t\t\tswimlanes.push(temp);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Selects ancestors for selected swimlanes
\t\t\t\tif (swimlanes.length > 0)
\t\t\t\t{
\t\t\t\t\tswimlanes = swimlanes.reverse();
\t\t\t\t\tswimlanes.splice(0, 0, cell);
\t\t\t\t\tswimlanes.push(cell);
\t\t\t\t\t
\t\t\t\t\tfor (var i = 0; i < swimlanes.length - 1; i++)
\t\t\t\t\t{
\t\t\t\t\t\tif (this.isCellSelected(swimlanes[i]))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcell = swimlanes[(this.isToggleEvent(evt)) ?
\t\t\t\t\t\t\t\ti : i + 1];
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t\t
\t\tif (cell != null)
\t\t{
\t\t\tthis.selectCellForEvent(cell, evt);
\t\t}
\t\telse if (!this.isToggleEvent(evt))
\t\t{
\t\t\tthis.clearSelection();
\t\t}
\t}
};

/**
 * Function: isSiblingSelected
 * 
 * Returns true if any sibling of the given cell is selected.
 */
mxGraph.prototype.isSiblingSelected = function(cell)
{
\tvar model = this.model;
\tvar parent = model.getParent(cell);
\tvar childCount = model.getChildCount(parent);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(parent, i);
\t\t
\t\tif (cell != child && this.isCellSelected(child))
\t\t{
\t\t\treturn true;
\t\t}
\t}
\t
\treturn false;
};


/**
 * Function: dblClick
 * 
 * Processes a doubleclick on an optional cell and fires a <dblclick>
 * event. The event is fired initially. If the graph is enabled and the
 * event has not been consumed, then <edit> is called with the given
 * cell. The event is ignored if no cell was specified.
 *
 * Example for overriding this method.
 *
 * (code)
 * graph.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())
 *   {
 * \t   mxUtils.alert('Hello, World!');
 *     mxe.consume();
 *   }
 * }
 * (end)
 * 
 * Example listener for this event.
 * 
 * (code)
 * graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt)
 * {
 *   var cell = evt.getProperty('cell');
 *   // do something with the cell and consume the
 *   // event to prevent in-place editing from start
 * });
 * (end) 
 * 
 * Parameters:
 * 
 * evt - Mouseevent that represents the doubleclick.
 * cell - Optional <mxCell> under the mousepointer.
 */
mxGraph.prototype.dblClick = function(evt, cell)
{
\tvar mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell);
\tthis.fireEvent(mxe);
\t
\t// Handles the event if it has not been consumed
\tif (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() &&
\t\tcell != null && this.isCellEditable(cell) && !this.isEditing(cell))
\t{
\t\tthis.startEditingAtCell(cell, evt);
\t\tmxEvent.consume(evt);
\t}
};

/**
 * Function: tapAndHold
 * 
 * Handles the <mxMouseEvent> by highlighting the <mxCellState>.
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> that represents the touch event.
 * state - Optional <mxCellState> that is associated with the event.
 */
mxGraph.prototype.tapAndHold = function(me)
{
\tvar evt = me.getEvent();
\tvar mxe = new mxEventObject(mxEvent.TAP_AND_HOLD, 'event', evt, 'cell', me.getCell());

\t// LATER: Check if event should be consumed if me is consumed
\tthis.fireEvent(mxe);

\tif (mxe.isConsumed())
\t{
\t\t// Resets the state of the panning handler
\t\tthis.panningHandler.panningTrigger = false;
\t}
\t
\t// Handles the event if it has not been consumed
\tif (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && this.connectionHandler.isEnabled())
\t{
\t\tvar state = this.view.getState(this.connectionHandler.marker.getCell(me));

\t\tif (state != null)
\t\t{
\t\t\tthis.connectionHandler.marker.currentColor = this.connectionHandler.marker.validColor;
\t\t\tthis.connectionHandler.marker.markedState = state;
\t\t\tthis.connectionHandler.marker.mark();
\t\t\t
\t\t\tthis.connectionHandler.first = new mxPoint(me.getGraphX(), me.getGraphY());
\t\t\tthis.connectionHandler.edgeState = this.connectionHandler.createEdgeState(me);
\t\t\tthis.connectionHandler.previous = state;
\t\t\tthis.connectionHandler.fireEvent(new mxEventObject(mxEvent.START, 'state', this.connectionHandler.previous));
\t\t}
\t}
};

/**
 * Function: scrollPointToVisible
 * 
 * Scrolls the graph to the given point, extending the graph container if
 * specified.
 */
mxGraph.prototype.scrollPointToVisible = function(x, y, extend, border)
{
\tif (!this.timerAutoScroll && (this.ignoreScrollbars || mxUtils.hasScrollbars(this.container)))
\t{
\t\tvar c = this.container;
\t\tborder = (border != null) ? border : 20;
\t\t
\t\tif (x >= c.scrollLeft && y >= c.scrollTop && x <= c.scrollLeft + c.clientWidth &&
\t\t\ty <= c.scrollTop + c.clientHeight)
\t\t{
\t\t\tvar dx = c.scrollLeft + c.clientWidth - x;
\t\t\t
\t\t\tif (dx < border)
\t\t\t{
\t\t\t\tvar old = c.scrollLeft;
\t\t\t\tc.scrollLeft += border - dx;

\t\t\t\t// Automatically extends the canvas size to the bottom, right
\t\t\t\t// if the event is outside of the canvas and the edge of the
\t\t\t\t// canvas has been reached. Notes: Needs fix for IE.
\t\t\t\tif (extend && old == c.scrollLeft)
\t\t\t\t{
\t\t\t\t\tif (this.dialect == mxConstants.DIALECT_SVG)
\t\t\t\t\t{
\t\t\t\t\t\tvar root = this.view.getDrawPane().ownerSVGElement;
\t\t\t\t\t\tvar width = this.container.scrollWidth + border - dx;
\t\t\t\t\t\t
\t\t\t\t\t\t// Updates the clipping region. This is an expensive
\t\t\t\t\t\t// operation that should not be executed too often.
\t\t\t\t\t\troot.style.width = width + 'px';
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tvar width = Math.max(c.clientWidth, c.scrollWidth) + border - dx;
\t\t\t\t\t\tvar canvas = this.view.getCanvas();
\t\t\t\t\t\tcanvas.style.width = width + 'px';
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tc.scrollLeft += border - dx;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdx = x - c.scrollLeft;
\t\t\t\t
\t\t\t\tif (dx < border)
\t\t\t\t{
\t\t\t\t\tc.scrollLeft -= border - dx;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar dy = c.scrollTop + c.clientHeight - y;
\t\t\t
\t\t\tif (dy < border)
\t\t\t{
\t\t\t\tvar old = c.scrollTop;
\t\t\t\tc.scrollTop += border - dy;

\t\t\t\tif (old == c.scrollTop && extend)
\t\t\t\t{
\t\t\t\t\tif (this.dialect == mxConstants.DIALECT_SVG)
\t\t\t\t\t{
\t\t\t\t\t\tvar root = this.view.getDrawPane().ownerSVGElement;
\t\t\t\t\t\tvar height = this.container.scrollHeight + border - dy;
\t\t\t\t\t\t
\t\t\t\t\t\t// Updates the clipping region. This is an expensive
\t\t\t\t\t\t// operation that should not be executed too often.
\t\t\t\t\t\troot.style.height = height + 'px';
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tvar height = Math.max(c.clientHeight, c.scrollHeight) + border - dy;
\t\t\t\t\t\tvar canvas = this.view.getCanvas();
\t\t\t\t\t\tcanvas.style.height = height + 'px';
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tc.scrollTop += border - dy;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdy = y - c.scrollTop;
\t\t\t\t
\t\t\t\tif (dy < border)
\t\t\t\t{
\t\t\t\t\tc.scrollTop -= border - dy;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\telse if (this.allowAutoPanning && !this.panningHandler.isActive())
\t{
\t\tif (this.panningManager == null)
\t\t{
\t\t\tthis.panningManager = this.createPanningManager();
\t\t}

\t\tthis.panningManager.panTo(x + this.panDx, y + this.panDy);
\t}
};


/**
 * Function: createPanningManager
 * 
 * Creates and returns an <mxPanningManager>.
 */
mxGraph.prototype.createPanningManager = function()
{
\treturn new mxPanningManager(this);
};

/**
 * Function: getBorderSizes
 * 
 * Returns the size of the border and padding on all four sides of the
 * container. The left, top, right and bottom borders are stored in the x, y,
 * width and height of the returned <mxRectangle>, respectively.
 */
mxGraph.prototype.getBorderSizes = function()
{
\tvar css = mxUtils.getCurrentStyle(this.container);
\t
\treturn new mxRectangle(mxUtils.parseCssNumber(css.paddingLeft) +
\t\t\t((css.borderLeftStyle != 'none') ? mxUtils.parseCssNumber(css.borderLeftWidth) : 0),
\t\tmxUtils.parseCssNumber(css.paddingTop) +
\t\t\t((css.borderTopStyle != 'none') ? mxUtils.parseCssNumber(css.borderTopWidth) : 0),
\t\tmxUtils.parseCssNumber(css.paddingRight) +
\t\t\t((css.borderRightStyle != 'none') ? mxUtils.parseCssNumber(css.borderRightWidth) : 0),
\t\tmxUtils.parseCssNumber(css.paddingBottom) +
\t\t\t((css.borderBottomStyle != 'none') ? mxUtils.parseCssNumber(css.borderBottomWidth) : 0));
};

/**
 * Function: getPreferredPageSize
 * 
 * Returns the preferred size of the background page if <preferPageSize> is true.
 */
mxGraph.prototype.getPreferredPageSize = function(bounds, width, height)
{
\tvar scale = this.view.scale;
\tvar tr = this.view.translate;
\tvar fmt = this.pageFormat;
\tvar ps = this.pageScale;
\tvar page = new mxRectangle(0, 0, Math.ceil(fmt.width * ps), Math.ceil(fmt.height * ps));
\t
\tvar hCount = (this.pageBreaksVisible) ? Math.ceil(width / page.width) : 1;
\tvar vCount = (this.pageBreaksVisible) ? Math.ceil(height / page.height) : 1;
\t
\treturn new mxRectangle(0, 0, hCount * page.width + 2 + tr.x, vCount * page.height + 2 + tr.y);
};

/**
 * Function: fit
 *
 * Scales the graph such that the complete diagram fits into <container> and
 * returns the current scale in the view. To fit an initial graph prior to
 * rendering, set <mxGraphView.rendering> to false prior to changing the model
 * and execute the following after changing the model.
 * 
 * (code)
 * graph.fit();
 * graph.view.rendering = true;
 * graph.refresh();
 * (end)
 * 
 * To fit and center the graph, the following code can be used.
 * 
 * (code)
 * var margin = 2;
 * var max = 3;
 * 
 * var bounds = graph.getGraphBounds();
 * var cw = graph.container.clientWidth - margin;
 * var ch = graph.container.clientHeight - margin;
 * var w = bounds.width / graph.view.scale;
 * var h = bounds.height / graph.view.scale;
 * var s = Math.min(max, Math.min(cw / w, ch / h));
 * 
 * graph.view.scaleAndTranslate(s,
 *   (margin + cw - w * s) / (2 * s) - bounds.x / graph.view.scale,
 *   (margin + ch - h * s) / (2 * s) - bounds.y / graph.view.scale);
 * (end)
 * 
 * Parameters:
 * 
 * border - Optional number that specifies the border. Default is <border>.
 * keepOrigin - Optional boolean that specifies if the translate should be
 * changed. Default is false.
 * margin - Optional margin in pixels. Default is 0.
 * enabled - Optional boolean that specifies if the scale should be set or
 * just returned. Default is true.
 * ignoreWidth - Optional boolean that specifies if the width should be
 * ignored. Default is false.
 * ignoreHeight - Optional boolean that specifies if the height should be
 * ignored. Default is false.
 * maxHeight - Optional maximum height.
 */
mxGraph.prototype.fit = function(border, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight)
{
\tif (this.container != null)
\t{
\t\tborder = (border != null) ? border : this.getBorder();
\t\tkeepOrigin = (keepOrigin != null) ? keepOrigin : false;
\t\tmargin = (margin != null) ? margin : 0;
\t\tenabled = (enabled != null) ? enabled : true;
\t\tignoreWidth = (ignoreWidth != null) ? ignoreWidth : false;
\t\tignoreHeight = (ignoreHeight != null) ? ignoreHeight : false;
\t\t
\t\t// Adds spacing and border from css
\t\tvar cssBorder = this.getBorderSizes();
\t\tvar w1 = this.container.offsetWidth - cssBorder.x - cssBorder.width - 1;
\t\tvar h1 = (maxHeight != null) ? maxHeight : this.container.offsetHeight - cssBorder.y - cssBorder.height - 1;
\t\tvar bounds = this.view.getGraphBounds();
\t\t
\t\tif (bounds.width > 0 && bounds.height > 0)
\t\t{
\t\t\tif (keepOrigin && bounds.x != null && bounds.y != null)
\t\t\t{
\t\t\t\tbounds = bounds.clone();
\t\t\t\tbounds.width += bounds.x;
\t\t\t\tbounds.height += bounds.y;
\t\t\t\tbounds.x = 0;
\t\t\t\tbounds.y = 0;
\t\t\t}
\t\t\t
\t\t\t// LATER: Use unscaled bounding boxes to fix rounding errors
\t\t\tvar s = this.view.scale;
\t\t\tvar w2 = bounds.width / s;
\t\t\tvar h2 = bounds.height / s;
\t\t\t
\t\t\t// Fits to the size of the background image if required
\t\t\tif (this.backgroundImage != null)
\t\t\t{
\t\t\t\tw2 = Math.max(w2, this.backgroundImage.width - bounds.x / s);
\t\t\t\th2 = Math.max(h2, this.backgroundImage.height - bounds.y / s);
\t\t\t}
\t\t\t
\t\t\tvar b = ((keepOrigin) ? border : 2 * border) + margin + 1;

\t\t\tw1 -= b;
\t\t\th1 -= b;
\t\t\t
\t\t\tvar s2 = (((ignoreWidth) ? h1 / h2 : (ignoreHeight) ? w1 / w2 :
\t\t\t\tMath.min(w1 / w2, h1 / h2)));
\t\t\t
\t\t\tif (this.minFitScale != null)
\t\t\t{
\t\t\t\ts2 = Math.max(s2, this.minFitScale);
\t\t\t}
\t\t\t
\t\t\tif (this.maxFitScale != null)
\t\t\t{
\t\t\t\ts2 = Math.min(s2, this.maxFitScale);
\t\t\t}
\t
\t\t\tif (enabled)
\t\t\t{
\t\t\t\tif (!keepOrigin)
\t\t\t\t{
\t\t\t\t\tif (!mxUtils.hasScrollbars(this.container))
\t\t\t\t\t{
\t\t\t\t\t\tvar x0 = (bounds.x != null) ? Math.floor(this.view.translate.x - bounds.x / s + border / s2 + margin / 2) : border;
\t\t\t\t\t\tvar y0 = (bounds.y != null) ? Math.floor(this.view.translate.y - bounds.y / s + border / s2 + margin / 2) : border;

\t\t\t\t\t\tthis.view.scaleAndTranslate(s2, x0, y0);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tthis.view.setScale(s2);
\t\t\t\t\t\tvar b2 = this.getGraphBounds();
\t\t\t\t\t\t
\t\t\t\t\t\tif (b2.x != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.container.scrollLeft = b2.x;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (b2.y != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.container.scrollTop = b2.y;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (this.view.scale != s2)
\t\t\t\t{
\t\t\t\t\tthis.view.setScale(s2);
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn s2;
\t\t\t}
\t\t}
\t}

\treturn this.view.scale;
};

/**
 * Function: sizeDidChange
 * 
 * Called when the size of the graph has changed. This implementation fires
 * a <size> event after updating the clipping region of the SVG element in
 * SVG-bases browsers.
 */
mxGraph.prototype.sizeDidChange = function()
{
\tvar bounds = this.getGraphBounds();
\t
\tif (this.container != null)
\t{
\t\tvar border = this.getBorder();
\t\t
\t\tvar width = Math.max(0, bounds.x) + bounds.width + 2 * border;
\t\tvar height = Math.max(0, bounds.y) + bounds.height + 2 * border;
\t\t
\t\tif (this.minimumContainerSize != null)
\t\t{
\t\t\twidth = Math.max(width, this.minimumContainerSize.width);
\t\t\theight = Math.max(height, this.minimumContainerSize.height);
\t\t}

\t\tif (this.resizeContainer)
\t\t{
\t\t\tthis.doResizeContainer(width, height);
\t\t}

\t\tif (this.preferPageSize || (!mxClient.IS_IE && this.pageVisible))
\t\t{
\t\t\tvar size = this.getPreferredPageSize(bounds, Math.max(1, width), Math.max(1, height));
\t\t\t
\t\t\tif (size != null)
\t\t\t{
\t\t\t\twidth = size.width * this.view.scale;
\t\t\t\theight = size.height * this.view.scale;
\t\t\t}
\t\t}
\t\t
\t\tif (this.minimumGraphSize != null)
\t\t{
\t\t\twidth = Math.max(width, this.minimumGraphSize.width * this.view.scale);
\t\t\theight = Math.max(height, this.minimumGraphSize.height * this.view.scale);
\t\t}

\t\twidth = Math.ceil(width);
\t\theight = Math.ceil(height);

\t\tif (this.dialect == mxConstants.DIALECT_SVG)
\t\t{
\t\t\tvar root = this.view.getDrawPane().ownerSVGElement;
\t\t\t
\t\t\tif (root != null)
\t\t\t{
\t\t\t\troot.style.minWidth = Math.max(1, width) + 'px';
\t\t\t\troot.style.minHeight = Math.max(1, height) + 'px';
\t\t\t\troot.style.width = '100%';
\t\t\t\troot.style.height = '100%';
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (mxClient.IS_QUIRKS)
\t\t\t{
\t\t\t\t// Quirks mode does not support minWidth/-Height
\t\t\t\tthis.view.updateHtmlCanvasSize(Math.max(1, width), Math.max(1, height));
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.view.canvas.style.minWidth = Math.max(1, width) + 'px';
\t\t\t\tthis.view.canvas.style.minHeight = Math.max(1, height) + 'px';
\t\t\t}
\t\t}
\t\t
\t\tthis.updatePageBreaks(this.pageBreaksVisible, width, height);
\t}

\tthis.fireEvent(new mxEventObject(mxEvent.SIZE, 'bounds', bounds));
};

/**
 * Function: doResizeContainer
 * 
 * Resizes the container for the given graph width and height.
 */
mxGraph.prototype.doResizeContainer = function(width, height)
{
\tif (this.maximumContainerSize != null)
\t{
\t\twidth = Math.min(this.maximumContainerSize.width, width);
\t\theight = Math.min(this.maximumContainerSize.height, height);
\t}

\tthis.container.style.width = Math.ceil(width) + 'px';
\tthis.container.style.height = Math.ceil(height) + 'px';
};

/**
 * Function: updatePageBreaks
 * 
 * Invokes from <sizeDidChange> to redraw the page breaks.
 * 
 * Parameters:
 * 
 * visible - Boolean that specifies if page breaks should be shown.
 * width - Specifies the width of the container in pixels.
 * height - Specifies the height of the container in pixels.
 */
mxGraph.prototype.updatePageBreaks = function(visible, width, height)
{
\tvar scale = this.view.scale;
\tvar tr = this.view.translate;
\tvar fmt = this.pageFormat;
\tvar ps = scale * this.pageScale;
\tvar bounds = new mxRectangle(0, 0, fmt.width * ps, fmt.height * ps);

\tvar gb = mxRectangle.fromRectangle(this.getGraphBounds());
\tgb.width = Math.max(1, gb.width);
\tgb.height = Math.max(1, gb.height);
\t
\tbounds.x = Math.floor((gb.x - tr.x * scale) / bounds.width) * bounds.width + tr.x * scale;
\tbounds.y = Math.floor((gb.y - tr.y * scale) / bounds.height) * bounds.height + tr.y * scale;
\t
\tgb.width = Math.ceil((gb.width + (gb.x - bounds.x)) / bounds.width) * bounds.width;
\tgb.height = Math.ceil((gb.height + (gb.y - bounds.y)) / bounds.height) * bounds.height;
\t
\t// Does not show page breaks if the scale is too small
\tvisible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;

\tvar horizontalCount = (visible) ? Math.ceil(gb.height / bounds.height) + 1 : 0;
\tvar verticalCount = (visible) ? Math.ceil(gb.width / bounds.width) + 1 : 0;
\tvar right = (verticalCount - 1) * bounds.width;
\tvar bottom = (horizontalCount - 1) * bounds.height;
\t
\tif (this.horizontalPageBreaks == null && horizontalCount > 0)
\t{
\t\tthis.horizontalPageBreaks = [];
\t}

\tif (this.verticalPageBreaks == null && verticalCount > 0)
\t{
\t\tthis.verticalPageBreaks = [];
\t}
\t
\tvar drawPageBreaks = mxUtils.bind(this, function(breaks)
\t{
\t\tif (breaks != null)
\t\t{
\t\t\tvar count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount; 
\t\t\t
\t\t\tfor (var i = 0; i <= count; i++)
\t\t\t{
\t\t\t\tvar pts = (breaks == this.horizontalPageBreaks) ?
\t\t\t\t\t[new mxPoint(Math.round(bounds.x), Math.round(bounds.y + i * bounds.height)),
\t\t\t         new mxPoint(Math.round(bounds.x + right), Math.round(bounds.y + i * bounds.height))] :
\t\t\t        [new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y)),
\t\t\t         new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y + bottom))];

\t\t\t\tif (breaks[i] != null)
\t\t\t\t{
\t\t\t\t\tbreaks[i].points = pts;
\t\t\t\t\tbreaks[i].redraw();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar pageBreak = new mxPolyline(pts, this.pageBreakColor);
\t\t\t\t\tpageBreak.dialect = this.dialect;
\t\t\t\t\tpageBreak.pointerEvents = false;
\t\t\t\t\tpageBreak.isDashed = this.pageBreakDashed;
\t\t\t\t\tpageBreak.init(this.view.backgroundPane);
\t\t\t\t\tpageBreak.redraw();
\t\t\t\t\t
\t\t\t\t\tbreaks[i] = pageBreak;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tfor (var i = count; i < breaks.length; i++)
\t\t\t{
\t\t\t\tbreaks[i].destroy();
\t\t\t}
\t\t\t
\t\t\tbreaks.splice(count, breaks.length - count);
\t\t}
\t});
\t
\tdrawPageBreaks(this.horizontalPageBreaks);
\tdrawPageBreaks(this.verticalPageBreaks);
};

/**
 * Group: Cell styles
 */

/**
 * Function: getCurrentCellStyle
 * 
 * Returns the style for the given cell from the cell state, if one exists,
 * or using <getCellStyle>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose style should be returned as an array.
 * ignoreState - Optional boolean that specifies if the cell state should be ignored.
 */
mxGraph.prototype.getCurrentCellStyle = function(cell, ignoreState)
{
\tvar state = (ignoreState) ? null : this.view.getState(cell);
\t
\treturn (state != null) ? state.style : this.getCellStyle(cell);
};

/**
 * Function: getCellStyle
 * 
 * Returns an array of key, value pairs representing the cell style for the
 * given cell. If no string is defined in the model that specifies the
 * style, then the default style for the cell is returned or an empty object,
 * if no style can be found. Note: You should try and get the cell state
 * for the given cell and use the cached style in the state before using
 * this method.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose style should be returned as an array.
 */
mxGraph.prototype.getCellStyle = function(cell)
{
\tvar stylename = this.model.getStyle(cell);
\tvar style = null;
\t
\t// Gets the default style for the cell
\tif (this.model.isEdge(cell))
\t{
\t\tstyle = this.stylesheet.getDefaultEdgeStyle();
\t}
\telse
\t{
\t\tstyle = this.stylesheet.getDefaultVertexStyle();
\t}
\t
\t// Resolves the stylename using the above as the default
\tif (stylename != null)
\t{
\t\tstyle = this.postProcessCellStyle(this.stylesheet.getCellStyle(stylename, style));
\t}
\t
\t// Returns a non-null value if no style can be found
\tif (style == null)
\t{
\t\tstyle = new Object();
\t}
\t
\treturn style;
};

/**
 * Function: postProcessCellStyle
 * 
 * Tries to resolve the value for the image style in the image bundles and
 * turns short data URIs as defined in mxImageBundle to data URIs as
 * defined in RFC 2397 of the IETF.
 */
mxGraph.prototype.postProcessCellStyle = function(style)
{
\tif (style != null)
\t{
\t\tvar key = style[mxConstants.STYLE_IMAGE];
\t\tvar image = this.getImageFromBundles(key);

\t\tif (image != null)
\t\t{
\t\t\tstyle[mxConstants.STYLE_IMAGE] = image;
\t\t}
\t\telse
\t\t{
\t\t\timage = key;
\t\t}
\t\t
\t\t// Converts short data uris to normal data uris
\t\tif (image != null && image.substring(0, 11) == 'data:image/')
\t\t{
\t\t\tif (image.substring(0, 20) == 'data:image/svg+xml,<')
\t\t\t{
\t\t\t\t// Required for FF and IE11
\t\t\t\timage = image.substring(0, 19) + encodeURIComponent(image.substring(19));
\t\t\t}
\t\t\telse if (image.substring(0, 22) != 'data:image/svg+xml,%3C')
\t\t\t{
\t\t\t\tvar comma = image.indexOf(',');
\t\t\t\t
\t\t\t\t// Adds base64 encoding prefix if needed
\t\t\t\tif (comma > 0 && image.substring(comma - 7, comma + 1) != ';base64,')
\t\t\t\t{
\t\t\t\t\timage = image.substring(0, comma) + ';base64,'
\t\t\t\t\t\t+ image.substring(comma + 1);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tstyle[mxConstants.STYLE_IMAGE] = image;
\t\t}
\t}

\treturn style;
};

/**
 * Function: setCellStyle
 * 
 * Sets the style of the specified cells. If no cells are given, then the
 * selection cells are changed.
 * 
 * Parameters:
 * 
 * style - String representing the new style of the cells.
 * cells - Optional array of <mxCells> to set the style for. Default is the
 * selection cells.
 */
mxGraph.prototype.setCellStyle = function(style, cells)
{
\tcells = cells || this.getSelectionCells();
\t
\tif (cells != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tthis.model.setStyle(cells[i], style);
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: toggleCellStyle
 * 
 * Toggles the boolean value for the given key in the style of the given cell
 * and returns the new value as 0 or 1. If no cell is specified then the
 * selection cell is used.
 * 
 * Parameter:
 * 
 * key - String representing the key for the boolean value to be toggled.
 * defaultValue - Optional boolean default value if no value is defined.
 * Default is false.
 * cell - Optional <mxCell> whose style should be modified. Default is
 * the selection cell.
 */
mxGraph.prototype.toggleCellStyle = function(key, defaultValue, cell)
{
\tcell = cell || this.getSelectionCell();
\t
\treturn this.toggleCellStyles(key, defaultValue, [cell]);
};

/**
 * Function: toggleCellStyles
 * 
 * Toggles the boolean value for the given key in the style of the given cells
 * and returns the new value as 0 or 1. If no cells are specified, then the
 * selection cells are used. For example, this can be used to toggle
 * <mxConstants.STYLE_ROUNDED> or any other style with a boolean value.
 * 
 * Parameter:
 * 
 * key - String representing the key for the boolean value to be toggled.
 * defaultValue - Optional boolean default value if no value is defined.
 * Default is false.
 * cells - Optional array of <mxCells> whose styles should be modified.
 * Default is the selection cells.
 */
mxGraph.prototype.toggleCellStyles = function(key, defaultValue, cells)
{
\tdefaultValue = (defaultValue != null) ? defaultValue : false;
\tcells = cells || this.getSelectionCells();
\tvar value = null;
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tvar style = this.getCurrentCellStyle(cells[0]);
\t\tvalue = (mxUtils.getValue(style, key, defaultValue)) ? 0 : 1;
\t\tthis.setCellStyles(key, value, cells);
\t}
\t
\treturn value;
};

/**
 * Function: setCellStyles
 * 
 * Sets the key to value in the styles of the given cells. This will modify
 * the existing cell styles in-place and override any existing assignment
 * for the given key. If no cells are specified, then the selection cells
 * are changed. If no value is specified, then the respective key is
 * removed from the styles.
 * 
 * Parameters:
 * 
 * key - String representing the key to be assigned.
 * value - String representing the new value for the key.
 * cells - Optional array of <mxCells> to change the style for. Default is
 * the selection cells.
 */
mxGraph.prototype.setCellStyles = function(key, value, cells)
{
\tcells = cells || this.getSelectionCells();
\tmxUtils.setCellStyles(this.model, cells, key, value);
};

/**
 * Function: toggleCellStyleFlags
 * 
 * Toggles the given bit for the given key in the styles of the specified
 * cells.
 * 
 * Parameters:
 * 
 * key - String representing the key to toggle the flag in.
 * flag - Integer that represents the bit to be toggled.
 * cells - Optional array of <mxCells> to change the style for. Default is
 * the selection cells.
 */
mxGraph.prototype.toggleCellStyleFlags = function(key, flag, cells)
{
\tthis.setCellStyleFlags(key, flag, null, cells);
};

/**
 * Function: setCellStyleFlags
 * 
 * Sets or toggles the given bit for the given key in the styles of the
 * specified cells.
 * 
 * Parameters:
 * 
 * key - String representing the key to toggle the flag in.
 * flag - Integer that represents the bit to be toggled.
 * value - Boolean value to be used or null if the value should be toggled.
 * cells - Optional array of <mxCells> to change the style for. Default is
 * the selection cells.
 */
mxGraph.prototype.setCellStyleFlags = function(key, flag, value, cells)
{
\tcells = cells || this.getSelectionCells();
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tif (value == null)
\t\t{
\t\t\tvar style = this.getCurrentCellStyle(cells[0]);
\t\t\tvar current = parseInt(style[key] || 0);
\t\t\tvalue = !((current & flag) == flag);
\t\t}

\t\tmxUtils.setCellStyleFlags(this.model, cells, key, flag, value);
\t}
};

/**
 * Group: Cell alignment and orientation
 */

/**
 * Function: alignCells
 * 
 * Aligns the given cells vertically or horizontally according to the given
 * alignment using the optional parameter as the coordinate.
 * 
 * Parameters:
 * 
 * align - Specifies the alignment. Possible values are all constants in
 * mxConstants with an ALIGN prefix.
 * cells - Array of <mxCells> to be aligned.
 * param - Optional coordinate for the alignment.
 */
mxGraph.prototype.alignCells = function(align, cells, param)
{
\tif (cells == null)
\t{
\t\tcells = this.getSelectionCells();
\t}
\t
\tif (cells != null && cells.length > 1)
\t{
\t\t// Finds the required coordinate for the alignment
\t\tif (param == null)
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar state = this.view.getState(cells[i]);
\t\t\t\t
\t\t\t\tif (state != null && !this.model.isEdge(cells[i]))
\t\t\t\t{
\t\t\t\t\tif (param == null)
\t\t\t\t\t{
\t\t\t\t\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.x + state.width / 2;
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.x + state.width;
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_TOP)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.y;
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_MIDDLE)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.y + state.height / 2;
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_BOTTOM)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.y + state.height;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = state.x;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tif (align == mxConstants.ALIGN_RIGHT)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = Math.max(param, state.x + state.width);
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_TOP)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = Math.min(param, state.y);
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (align == mxConstants.ALIGN_BOTTOM)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = Math.max(param, state.y + state.height);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tparam = Math.min(param, state.x);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Aligns the cells to the coordinate
\t\tif (param != null)
\t\t{
\t\t\tvar s = this.view.scale;

\t\t\tthis.model.beginUpdate();
\t\t\ttry
\t\t\t{
\t\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t\t{
\t\t\t\t\tvar state = this.view.getState(cells[i]);
\t\t\t\t\t
\t\t\t\t\tif (state != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar geo = this.getCellGeometry(cells[i]);
\t\t\t\t\t\t
\t\t\t\t\t\tif (geo != null && !this.model.isEdge(cells[i]))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (align == mxConstants.ALIGN_CENTER)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.x += (param - state.x - state.width / 2) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (align == mxConstants.ALIGN_RIGHT)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.x += (param - state.x - state.width) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (align == mxConstants.ALIGN_TOP)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.y += (param - state.y) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (align == mxConstants.ALIGN_MIDDLE)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.y += (param - state.y - state.height / 2) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (align == mxConstants.ALIGN_BOTTOM)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.y += (param - state.y - state.height) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.x += (param - state.x) / s;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tthis.resizeCell(cells[i], geo);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.ALIGN_CELLS,
\t\t\t\t\t\t'align', align, 'cells', cells));
\t\t\t}
\t\t\tfinally
\t\t\t{
\t\t\t\tthis.model.endUpdate();
\t\t\t}
\t\t}
\t}
\t
\treturn cells;
};

/**
 * Function: flipEdge
 * 
 * Toggles the style of the given edge between null (or empty) and
 * <alternateEdgeStyle>. This method fires <mxEvent.FLIP_EDGE> while the
 * transaction is in progress. Returns the edge that was flipped.
 * 
 * Here is an example that overrides this implementation to invert the
 * value of <mxConstants.STYLE_ELBOW> without removing any existing styles.
 * 
 * (code)
 * graph.flipEdge = function(edge)
 * {
 *   if (edge != null)
 *   {
 *     var style = this.getCurrentCellStyle(edge);
 *     var elbow = mxUtils.getValue(style, mxConstants.STYLE_ELBOW,
 *         mxConstants.ELBOW_HORIZONTAL);
 *     var value = (elbow == mxConstants.ELBOW_HORIZONTAL) ?
 *         mxConstants.ELBOW_VERTICAL : mxConstants.ELBOW_HORIZONTAL;
 *     this.setCellStyles(mxConstants.STYLE_ELBOW, value, [edge]);
 *   }
 * };
 * (end)
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose style should be changed.
 */
mxGraph.prototype.flipEdge = function(edge)
{
\tif (edge != null &&
\t\tthis.alternateEdgeStyle != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tvar style = this.model.getStyle(edge);

\t\t\tif (style == null || style.length == 0)
\t\t\t{
\t\t\t\tthis.model.setStyle(edge, this.alternateEdgeStyle);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.model.setStyle(edge, null);
\t\t\t}

\t\t\t// Removes all existing control points
\t\t\tthis.resetEdge(edge);
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.FLIP_EDGE, 'edge', edge));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}

\treturn edge;
};

/**
 * Function: addImageBundle
 *
 * Adds the specified <mxImageBundle>.
 */
mxGraph.prototype.addImageBundle = function(bundle)
{
\tthis.imageBundles.push(bundle);
};

/**
 * Function: removeImageBundle
 * 
 * Removes the specified <mxImageBundle>.
 */
mxGraph.prototype.removeImageBundle = function(bundle)
{
\tvar tmp = [];
\t
\tfor (var i = 0; i < this.imageBundles.length; i++)
\t{
\t\tif (this.imageBundles[i] != bundle)
\t\t{
\t\t\ttmp.push(this.imageBundles[i]);
\t\t}
\t}
\t
\tthis.imageBundles = tmp;
};

/**
 * Function: getImageFromBundles
 *
 * Searches all <imageBundles> for the specified key and returns the value
 * for the first match or null if the key is not found.
 */
mxGraph.prototype.getImageFromBundles = function(key)
{
\tif (key != null)
\t{
\t\tfor (var i = 0; i < this.imageBundles.length; i++)
\t\t{
\t\t\tvar image = this.imageBundles[i].getImage(key);
\t\t\t
\t\t\tif (image != null)
\t\t\t{
\t\t\t\treturn image;
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Group: Order
 */

/**
 * Function: orderCells
 * 
 * Moves the given cells to the front or back. The change is carried out
 * using <cellsOrdered>. This method fires <mxEvent.ORDER_CELLS> while the
 * transaction is in progress.
 * 
 * Parameters:
 * 
 * back - Boolean that specifies if the cells should be moved to back.
 * cells - Array of <mxCells> to move to the background. If null is
 * specified then the selection cells are used.
 */
mxGraph.prototype.orderCells = function(back, cells)
{
\tif (cells == null)
\t{
\t\tcells = mxUtils.sortCells(this.getSelectionCells(), true);
\t}

\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.cellsOrdered(cells, back);
\t\tthis.fireEvent(new mxEventObject(mxEvent.ORDER_CELLS,
\t\t\t\t'back', back, 'cells', cells));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: cellsOrdered
 * 
 * Moves the given cells to the front or back. This method fires
 * <mxEvent.CELLS_ORDERED> while the transaction is in progress.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose order should be changed.
 * back - Boolean that specifies if the cells should be moved to back.
 */
mxGraph.prototype.cellsOrdered = function(cells, back)
{
\tif (cells != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar parent = this.model.getParent(cells[i]);

\t\t\t\tif (back)
\t\t\t\t{
\t\t\t\t\tthis.model.add(parent, cells[i], i);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.model.add(parent, cells[i],
\t\t\t\t\t\t\tthis.model.getChildCount(parent) - 1);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_ORDERED,
\t\t\t\t\t'back', back, 'cells', cells));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Group: Grouping
 */

/**
 * Function: groupCells
 * 
 * Adds the cells into the given group. The change is carried out using
 * <cellsAdded>, <cellsMoved> and <cellsResized>. This method fires
 * <mxEvent.GROUP_CELLS> while the transaction is in progress. Returns the
 * new group. A group is only created if there is at least one entry in the
 * given array of cells.
 * 
 * Parameters:
 * 
 * group - <mxCell> that represents the target group. If null is specified
 * then a new group is created using <createGroupCell>.
 * border - Optional integer that specifies the border between the child
 * area and the group bounds. Default is 0.
 * cells - Optional array of <mxCells> to be grouped. If null is specified
 * then the selection cells are used.
 */
mxGraph.prototype.groupCells = function(group, border, cells)
{
\tif (cells == null)
\t{
\t\tcells = mxUtils.sortCells(this.getSelectionCells(), true);
\t}

\tcells = this.getCellsForGroup(cells);

\tif (group == null)
\t{
\t\tgroup = this.createGroupCell(cells);
\t}

\tvar bounds = this.getBoundsForGroup(group, cells, border);

\tif (cells.length > 1 && bounds != null)
\t{
\t\t// Uses parent of group or previous parent of first child
\t\tvar parent = this.model.getParent(group);
\t\t
\t\tif (parent == null)
\t\t{
\t\t\tparent = this.model.getParent(cells[0]);
\t\t}

\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\t// Checks if the group has a geometry and
\t\t\t// creates one if one does not exist
\t\t\tif (this.getCellGeometry(group) == null)
\t\t\t{
\t\t\t\tthis.model.setGeometry(group, new mxGeometry());
\t\t\t}

\t\t\t// Adds the group into the parent
\t\t\tvar index = this.model.getChildCount(parent);
\t\t\tthis.cellsAdded([group], parent, index, null, null, false, false, false);

\t\t\t// Adds the children into the group and moves
\t\t\tindex = this.model.getChildCount(group);
\t\t\tthis.cellsAdded(cells, group, index, null, null, false, false, false);
\t\t\tthis.cellsMoved(cells, -bounds.x, -bounds.y, false, false, false);

\t\t\t// Resizes the group
\t\t\tthis.cellsResized([group], [bounds], false);

\t\t\tthis.fireEvent(new mxEventObject(mxEvent.GROUP_CELLS,
\t\t\t\t\t'group', group, 'border', border, 'cells', cells));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}

\treturn group;
};

/**
 * Function: getCellsForGroup
 * 
 * Returns the cells with the same parent as the first cell
 * in the given array.
 */
mxGraph.prototype.getCellsForGroup = function(cells)
{
\tvar result = [];

\tif (cells != null && cells.length > 0)
\t{
\t\tvar parent = this.model.getParent(cells[0]);
\t\tresult.push(cells[0]);

\t\t// Filters selection cells with the same parent
\t\tfor (var i = 1; i < cells.length; i++)
\t\t{
\t\t\tif (this.model.getParent(cells[i]) == parent)
\t\t\t{
\t\t\t\tresult.push(cells[i]);
\t\t\t}
\t\t}
\t}

\treturn result;
};

/**
 * Function: getBoundsForGroup
 * 
 * Returns the bounds to be used for the given group and children.
 */
mxGraph.prototype.getBoundsForGroup = function(group, children, border)
{
\tvar result = this.getBoundingBoxFromGeometry(children, true);
\t
\tif (result != null)
\t{
\t\tif (this.isSwimlane(group))
\t\t{
\t\t\tvar size = this.getStartSize(group);
\t\t\t
\t\t\tresult.x -= size.width;
\t\t\tresult.y -= size.height;
\t\t\tresult.width += size.width;
\t\t\tresult.height += size.height;
\t\t}
\t\t
\t\t// Adds the border
\t\tif (border != null)
\t\t{
\t\t\tresult.x -= border;
\t\t\tresult.y -= border;
\t\t\tresult.width += 2 * border;
\t\t\tresult.height += 2 * border;
\t\t}
\t}\t\t\t
\t
\treturn result;
};

/**
 * Function: createGroupCell
 * 
 * Hook for creating the group cell to hold the given array of <mxCells> if
 * no group cell was given to the <group> function.
 * 
 * The following code can be used to set the style of new group cells.
 * 
 * (code)
 * var graphCreateGroupCell = graph.createGroupCell;
 * graph.createGroupCell = function(cells)
 * {
 *   var group = graphCreateGroupCell.apply(this, arguments);
 *   group.setStyle('group');
 *   
 *   return group;
 * };
 */
mxGraph.prototype.createGroupCell = function(cells)
{
\tvar group = new mxCell('');
\tgroup.setVertex(true);
\tgroup.setConnectable(false);
\t
\treturn group;
};

/**
 * Function: ungroupCells
 * 
 * Ungroups the given cells by moving the children the children to their
 * parents parent and removing the empty groups. Returns the children that
 * have been removed from the groups.
 * 
 * Parameters:
 * 
 * cells - Array of cells to be ungrouped. If null is specified then the
 * selection cells are used.
 */
mxGraph.prototype.ungroupCells = function(cells)
{
\tvar result = [];
\t
\tif (cells == null)
\t{
\t\tcells = this.getCellsForUngroup();
\t}
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar children = this.model.getChildren(cells[i]);
\t\t\t\t
\t\t\t\tif (children != null && children.length > 0)
\t\t\t\t{
\t\t\t\t\tchildren = children.slice();
\t\t\t\t\tvar parent = this.model.getParent(cells[i]);
\t\t\t\t\tvar index = this.model.getChildCount(parent);

\t\t\t\t\tthis.cellsAdded(children, parent, index, null, null, true);
\t\t\t\t\tresult = result.concat(children);
\t\t\t\t\t
\t\t\t\t\t// Fix relative child cells
\t\t\t\t\tfor (var j = 0; j < children.length; j++)
\t\t\t\t\t{
\t\t\t\t\t\tvar state = this.view.getState(children[j]);
\t\t\t\t\t\tvar geo = this.getCellGeometry(children[j]);
\t\t\t\t\t\t
\t\t\t\t\t\tif (state != null && geo != null && geo.relative)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\tgeo.x = state.origin.x;
\t\t\t\t\t\t\tgeo.y = state.origin.y;
\t\t\t\t\t\t\tgeo.relative = false;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tthis.model.setGeometry(children[j], geo);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tthis.removeCellsAfterUngroup(cells);
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.UNGROUP_CELLS, 'cells', cells));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getCellsForUngroup
 * 
 * Returns the selection cells that can be ungrouped.
 */
mxGraph.prototype.getCellsForUngroup = function()
{
\tvar cells = this.getSelectionCells();

\t// Finds the cells with children
\tvar tmp = [];
\t
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tif (this.model.isVertex(cells[i]) &&
\t\t\tthis.model.getChildCount(cells[i]) > 0)
\t\t{
\t\t\ttmp.push(cells[i]);
\t\t}
\t}

\treturn tmp;
};

/**
 * Function: removeCellsAfterUngroup
 * 
 * Hook to remove the groups after <ungroupCells>.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> that were ungrouped.
 */
mxGraph.prototype.removeCellsAfterUngroup = function(cells)
{
\tthis.cellsRemoved(this.addAllEdges(cells));
};

/**
 * Function: removeCellsFromParent
 * 
 * Removes the specified cells from their parents and adds them to the
 * default parent. Returns the cells that were removed from their parents.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be removed from their parents.
 */
mxGraph.prototype.removeCellsFromParent = function(cells)
{
\tif (cells == null)
\t{
\t\tcells = this.getSelectionCells();
\t}
\t
\tthis.model.beginUpdate();
\ttry
\t{
\t\tvar parent = this.getDefaultParent();
\t\tvar index = this.model.getChildCount(parent);

\t\tthis.cellsAdded(cells, parent, index, null, null, true);
\t\tthis.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS_FROM_PARENT, 'cells', cells));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: updateGroupBounds
 * 
 * Updates the bounds of the given groups to include all children and returns
 * the passed-in cells. Call this with the groups in parent to child order,
 * top-most group first, the cells are processed in reverse order and cells
 * with no children are ignored.
 * 
 * Parameters:
 * 
 * cells - The groups whose bounds should be updated. If this is null, then
 * the selection cells are used.
 * border - Optional border to be added in the group. Default is 0.
 * moveGroup - Optional boolean that allows the group to be moved. Default
 * is false.
 * topBorder - Optional top border to be added in the group. Default is 0.
 * rightBorder - Optional top border to be added in the group. Default is 0.
 * bottomBorder - Optional top border to be added in the group. Default is 0.
 * leftBorder - Optional top border to be added in the group. Default is 0.
 */
mxGraph.prototype.updateGroupBounds = function(cells, border, moveGroup, topBorder, rightBorder, bottomBorder, leftBorder)
{
\tif (cells == null)
\t{
\t\tcells = this.getSelectionCells();
\t}
\t
\tborder = (border != null) ? border : 0;
\tmoveGroup = (moveGroup != null) ? moveGroup : false;
\ttopBorder = (topBorder != null) ? topBorder : 0;
\trightBorder = (rightBorder != null) ? rightBorder : 0;
\tbottomBorder = (bottomBorder != null) ? bottomBorder : 0;
\tleftBorder = (leftBorder != null) ? leftBorder : 0;

\tthis.model.beginUpdate();
\ttry
\t{
\t\tfor (var i = cells.length - 1; i >= 0; i--)
\t\t{
\t\t\tvar geo = this.getCellGeometry(cells[i]);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tvar children = this.getChildCells(cells[i]);
\t\t\t\t
\t\t\t\tif (children != null && children.length > 0)
\t\t\t\t{
\t\t\t\t\tvar bounds = this.getBoundingBoxFromGeometry(children, true);
\t\t\t\t\t
\t\t\t\t\tif (bounds != null && bounds.width > 0 && bounds.height > 0)
\t\t\t\t\t{
\t\t\t\t\t\t// Adds the size of the title area for swimlanes
\t\t\t\t\t\tvar size = (this.isSwimlane(cells[i])) ?
\t\t\t\t\t\t\tthis.getActualStartSize(cells[i], true) : new mxRectangle();
\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t
\t\t\t\t\t\tif (moveGroup)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.x = Math.round(geo.x + bounds.x - border - size.x - leftBorder);
\t\t\t\t\t\t\tgeo.y = Math.round(geo.y + bounds.y - border - size.y - topBorder);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tgeo.width = Math.round(bounds.width + 2 * border + size.x + leftBorder + rightBorder + size.width);
\t\t\t\t\t\tgeo.height = Math.round(bounds.height + 2 * border + size.y + topBorder + bottomBorder + size.height);
\t\t\t\t\t\t
\t\t\t\t\t\tthis.model.setGeometry(cells[i], geo);
\t\t\t\t\t\tthis.moveCells(children, border + size.x - bounds.x + leftBorder,
\t\t\t\t\t\t\t\tborder + size.y - bounds.y + topBorder);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: getBoundingBox
 * 
 * Returns the bounding box for the given array of <mxCells>. The bounding box for
 * each cell and its descendants is computed using <mxGraphView.getBoundingBox>.
 *
 * Parameters:
 *
 * cells - Array of <mxCells> whose bounding box should be returned.
 */
mxGraph.prototype.getBoundingBox = function(cells)
{
\tvar result = null;
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (this.model.isVertex(cells[i]) || this.model.isEdge(cells[i]))
\t\t\t{
\t\t\t\tvar bbox = this.view.getBoundingBox(this.view.getState(cells[i]), true);
\t\t\t
\t\t\t\tif (bbox != null)
\t\t\t\t{
\t\t\t\t\tif (result == null)
\t\t\t\t\t{
\t\t\t\t\t\tresult = mxRectangle.fromRectangle(bbox);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tresult.add(bbox);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Group: Cell cloning, insertion and removal
 */

/**
 * Function: cloneCell
 * 
 * Returns the clone for the given cell. Uses <cloneCells>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be cloned.
 * allowInvalidEdges - Optional boolean that specifies if invalid edges
 * should be cloned. Default is true.
 * mapping - Optional mapping for existing clones.
 * keepPosition - Optional boolean indicating if the position of the cells should
 * be updated to reflect the lost parent cell. Default is false.
 */
mxGraph.prototype.cloneCell = function(cell, allowInvalidEdges, mapping, keepPosition)
{
\treturn this.cloneCells([cell], allowInvalidEdges, mapping, keepPosition)[0];
};

/**
 * Function: cloneCells
 * 
 * Returns the clones for the given cells. The clones are created recursively
 * using <mxGraphModel.cloneCells>. If the terminal of an edge is not in the
 * given array, then the respective end is assigned a terminal point and the
 * terminal is removed.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be cloned.
 * allowInvalidEdges - Optional boolean that specifies if invalid edges
 * should be cloned. Default is true.
 * mapping - Optional mapping for existing clones.
 * keepPosition - Optional boolean indicating if the position of the cells should
 * be updated to reflect the lost parent cell. Default is false.
 */
mxGraph.prototype.cloneCells = function(cells, allowInvalidEdges, mapping, keepPosition)
{
\tallowInvalidEdges = (allowInvalidEdges != null) ? allowInvalidEdges : true;
\tvar clones = null;
\t
\tif (cells != null)
\t{
\t\t// Creates a dictionary for fast lookups
\t\tvar dict = new mxDictionary();
\t\tvar tmp = [];
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tdict.put(cells[i], true);
\t\t\ttmp.push(cells[i]);
\t\t}
\t\t
\t\tif (tmp.length > 0)
\t\t{
\t\t\tvar scale = this.view.scale;
\t\t\tvar trans = this.view.translate;
\t\t\tclones = this.model.cloneCells(cells, true, mapping);
\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (!allowInvalidEdges && this.model.isEdge(clones[i]) &&
\t\t\t\t\tthis.getEdgeValidationError(clones[i],
\t\t\t\t\t\tthis.model.getTerminal(clones[i], true),
\t\t\t\t\t\tthis.model.getTerminal(clones[i], false)) != null)
\t\t\t\t{
\t\t\t\t\tclones[i] = null;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar g = this.model.getGeometry(clones[i]);
\t\t\t\t\t
\t\t\t\t\tif (g != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar state = this.view.getState(cells[i]);
\t\t\t\t\t\tvar pstate = this.view.getState(this.model.getParent(cells[i]));
\t\t\t\t\t\t
\t\t\t\t\t\tif (state != null && pstate != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar dx = (keepPosition) ? 0 : pstate.origin.x;
\t\t\t\t\t\t\tvar dy = (keepPosition) ? 0 : pstate.origin.y;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (this.model.isEdge(clones[i]))
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar pts = state.absolutePoints;
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (pts != null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t// Checks if the source is cloned or sets the terminal point
\t\t\t\t\t\t\t\t\tvar src = this.model.getTerminal(cells[i], true);
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\twhile (src != null && !dict.get(src))
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tsrc = this.model.getParent(src);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (src == null && pts[0] != null)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tg.setTerminalPoint(
\t\t\t\t\t\t\t\t\t\t\tnew mxPoint(pts[0].x / scale - trans.x,
\t\t\t\t\t\t\t\t\t\t\t\tpts[0].y / scale - trans.y), true);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t// Checks if the target is cloned or sets the terminal point
\t\t\t\t\t\t\t\t\tvar trg = this.model.getTerminal(cells[i], false);
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\twhile (trg != null && !dict.get(trg))
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\ttrg = this.model.getParent(trg);
\t\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\t\tvar n = pts.length - 1;
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (trg == null && pts[n] != null)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tg.setTerminalPoint(
\t\t\t\t\t\t\t\t\t\t\tnew mxPoint(pts[n].x / scale - trans.x,
\t\t\t\t\t\t\t\t\t\t\t\tpts[n].y / scale - trans.y), false);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t// Translates the control points
\t\t\t\t\t\t\t\t\tvar points = g.points;
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (points != null)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tfor (var j = 0; j < points.length; j++)
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tpoints[j].x += dx;
\t\t\t\t\t\t\t\t\t\t\tpoints[j].y += dy;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tg.translate(dx, dy);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tclones = [];
\t\t}
\t}
\t
\treturn clones;
};

/**
 * Function: insertVertex
 * 
 * Adds a new vertex into the given parent <mxCell> using value as the user
 * object and the given coordinates as the <mxGeometry> of the new vertex.
 * The id and style are used for the respective properties of the new
 * <mxCell>, which is returned.
 *
 * When adding new vertices from a mouse event, one should take into
 * account the offset of the graph container and the scale and translation
 * of the view in order to find the correct unscaled, untranslated
 * coordinates using <mxGraph.getPointForEvent> as follows:
 * 
 * (code)
 * var pt = graph.getPointForEvent(evt);
 * var parent = graph.getDefaultParent();
 * graph.insertVertex(parent, null,
 * \t\t\t'Hello, World!', x, y, 220, 30);
 * (end)
 * 
 * For adding image cells, the style parameter can be assigned as
 * 
 * (code)
 * stylename;image=imageUrl
 * (end)
 * 
 * See <mxGraph> for more information on using images.
 *
 * Parameters:
 * 
 * parent - <mxCell> that specifies the parent of the new vertex.
 * id - Optional string that defines the Id of the new vertex.
 * value - Object to be used as the user object.
 * x - Integer that defines the x coordinate of the vertex.
 * y - Integer that defines the y coordinate of the vertex.
 * width - Integer that defines the width of the vertex.
 * height - Integer that defines the height of the vertex.
 * style - Optional string that defines the cell style.
 * relative - Optional boolean that specifies if the geometry is relative.
 * Default is false.
 */
mxGraph.prototype.insertVertex = function(parent, id, value,
\tx, y, width, height, style, relative)
{
\tvar vertex = this.createVertex(parent, id, value, x, y, width, height, style, relative);

\treturn this.addCell(vertex, parent);
};

/**
 * Function: createVertex
 * 
 * Hook method that creates the new vertex for <insertVertex>.
 */
mxGraph.prototype.createVertex = function(parent, id, value,
\t\tx, y, width, height, style, relative)
{
\t// Creates the geometry for the vertex
\tvar geometry = new mxGeometry(x, y, width, height);
\tgeometry.relative = (relative != null) ? relative : false;
\t
\t// Creates the vertex
\tvar vertex = new mxCell(value, geometry, style);
\tvertex.setId(id);
\tvertex.setVertex(true);
\tvertex.setConnectable(true);
\t
\treturn vertex;
};
\t
/**
 * Function: insertEdge
 * 
 * Adds a new edge into the given parent <mxCell> using value as the user
 * object and the given source and target as the terminals of the new edge.
 * The id and style are used for the respective properties of the new
 * <mxCell>, which is returned.
 *
 * Parameters:
 * 
 * parent - <mxCell> that specifies the parent of the new edge.
 * id - Optional string that defines the Id of the new edge.
 * value - JavaScript object to be used as the user object.
 * source - <mxCell> that defines the source of the edge.
 * target - <mxCell> that defines the target of the edge.
 * style - Optional string that defines the cell style.
 */
mxGraph.prototype.insertEdge = function(parent, id, value, source, target, style)
{
\tvar edge = this.createEdge(parent, id, value, source, target, style);
\t
\treturn this.addEdge(edge, parent, source, target);
};

/**
 * Function: createEdge
 * 
 * Hook method that creates the new edge for <insertEdge>. This
 * implementation does not set the source and target of the edge, these
 * are set when the edge is added to the model.
 * 
 */
mxGraph.prototype.createEdge = function(parent, id, value, source, target, style)
{
\t// Creates the edge
\tvar edge = new mxCell(value, new mxGeometry(), style);
\tedge.setId(id);
\tedge.setEdge(true);
\tedge.geometry.relative = true;
\t
\treturn edge;
};

/**
 * Function: addEdge
 * 
 * Adds the edge to the parent and connects it to the given source and
 * target terminals. This is a shortcut method. Returns the edge that was
 * added.
 * 
 * Parameters:
 * 
 * edge - <mxCell> to be inserted into the given parent.
 * parent - <mxCell> that represents the new parent. If no parent is
 * given then the default parent is used.
 * source - Optional <mxCell> that represents the source terminal.
 * target - Optional <mxCell> that represents the target terminal.
 * index - Optional index to insert the cells at. Default is to append.
 */
mxGraph.prototype.addEdge = function(edge, parent, source, target, index)
{
\treturn this.addCell(edge, parent, index, source, target);
};

/**
 * Function: addCell
 * 
 * Adds the cell to the parent and connects it to the given source and
 * target terminals. This is a shortcut method. Returns the cell that was
 * added.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be inserted into the given parent.
 * parent - <mxCell> that represents the new parent. If no parent is
 * given then the default parent is used.
 * index - Optional index to insert the cells at. Default is to append.
 * source - Optional <mxCell> that represents the source terminal.
 * target - Optional <mxCell> that represents the target terminal.
 */
mxGraph.prototype.addCell = function(cell, parent, index, source, target)
{
\treturn this.addCells([cell], parent, index, source, target)[0];
};

/**
 * Function: addCells
 * 
 * Adds the cells to the parent at the given index, connecting each cell to
 * the optional source and target terminal. The change is carried out using
 * <cellsAdded>. This method fires <mxEvent.ADD_CELLS> while the
 * transaction is in progress. Returns the cells that were added.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be inserted.
 * parent - <mxCell> that represents the new parent. If no parent is
 * given then the default parent is used.
 * index - Optional index to insert the cells at. Default is to append.
 * source - Optional source <mxCell> for all inserted cells.
 * target - Optional target <mxCell> for all inserted cells.
 * absolute - Optional boolean indicating of cells should be kept at
 * their absolute position. Default is false.
 */
mxGraph.prototype.addCells = function(cells, parent, index, source, target, absolute)
{
\tif (parent == null)
\t{
\t\tparent = this.getDefaultParent();
\t}
\t
\tif (index == null)
\t{
\t\tindex = this.model.getChildCount(parent);
\t}
\t
\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.cellsAdded(cells, parent, index, source, target, (absolute != null) ? absolute : false, true);
\t\tthis.fireEvent(new mxEventObject(mxEvent.ADD_CELLS, 'cells', cells,
\t\t\t\t'parent', parent, 'index', index, 'source', source, 'target', target));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: cellsAdded
 * 
 * Adds the specified cells to the given parent. This method fires
 * <mxEvent.CELLS_ADDED> while the transaction is in progress.
 */
mxGraph.prototype.cellsAdded = function(cells, parent, index, source, target, absolute, constrain, extend)
{
\tif (cells != null && parent != null && index != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tvar parentState = (absolute) ? this.view.getState(parent) : null;
\t\t\tvar o1 = (parentState != null) ? parentState.origin : null;
\t\t\tvar zero = new mxPoint(0, 0);

\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (cells[i] == null)
\t\t\t\t{
\t\t\t\t\tindex--;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar previous = this.model.getParent(cells[i]);
\t
\t\t\t\t\t// Keeps the cell at its absolute location
\t\t\t\t\tif (o1 != null && cells[i] != parent && parent != previous)
\t\t\t\t\t{
\t\t\t\t\t\tvar oldState = this.view.getState(previous);
\t\t\t\t\t\tvar o2 = (oldState != null) ? oldState.origin : zero;
\t\t\t\t\t\tvar geo = this.model.getGeometry(cells[i]);
\t
\t\t\t\t\t\tif (geo != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar dx = o2.x - o1.x;
\t\t\t\t\t\t\tvar dy = o2.y - o1.y;
\t
\t\t\t\t\t\t\t// FIXME: Cells should always be inserted first before any other edit
\t\t\t\t\t\t\t// to avoid forward references in sessions.
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\tgeo.translate(dx, dy);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (!geo.relative && this.model.isVertex(cells[i]) &&
\t\t\t\t\t\t\t\t!this.isAllowNegativeCoordinates())
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.x = Math.max(0, geo.x);
\t\t\t\t\t\t\t\tgeo.y = Math.max(0, geo.y);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tthis.model.setGeometry(cells[i], geo);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t
\t\t\t\t\t// Decrements all following indices
\t\t\t\t\t// if cell is already in parent
\t\t\t\t\tif (parent == previous && index + i > this.model.getChildCount(parent))
\t\t\t\t\t{
\t\t\t\t\t\tindex--;
\t\t\t\t\t}

\t\t\t\t\tthis.model.add(parent, cells[i], index + i);
\t\t\t\t\t
\t\t\t\t\tif (this.autoSizeCellsOnAdd)
\t\t\t\t\t{
\t\t\t\t\t\tthis.autoSizeCell(cells[i], true);
\t\t\t\t\t}

\t\t\t\t\t// Extends the parent or constrains the child
\t\t\t\t\tif ((extend == null || extend) &&
\t\t\t\t\t\tthis.isExtendParentsOnAdd(cells[i]) && this.isExtendParent(cells[i]))
\t\t\t\t\t{
\t\t\t\t\t\tthis.extendParent(cells[i]);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Additionally constrains the child after extending the parent
\t\t\t\t\tif (constrain == null || constrain)
\t\t\t\t\t{
\t\t\t\t\t\tthis.constrainChild(cells[i]);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Sets the source terminal
\t\t\t\t\tif (source != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.cellConnected(cells[i], source, true);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Sets the target terminal
\t\t\t\t\tif (target != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.cellConnected(cells[i], target, false);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_ADDED, 'cells', cells,
\t\t\t\t'parent', parent, 'index', index, 'source', source, 'target', target,
\t\t\t\t'absolute', absolute));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: autoSizeCell
 * 
 * Resizes the specified cell to just fit around the its label and/or children
 * 
 * Parameters:
 * 
 * cell - <mxCells> to be resized.
 * recurse - Optional boolean which specifies if all descendants should be
 * autosized. Default is true.
 */
mxGraph.prototype.autoSizeCell = function(cell, recurse)
{
\trecurse = (recurse != null) ? recurse : true;
\t
\tif (recurse)
\t{
\t\tvar childCount = this.model.getChildCount(cell);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tthis.autoSizeCell(this.model.getChildAt(cell, i));
\t\t}
\t}

\tif (this.getModel().isVertex(cell) && this.isAutoSizeCell(cell))
\t{
\t\tthis.updateCellSize(cell);
\t}
};

/**
 * Function: removeCells
 * 
 * Removes the given cells from the graph including all connected edges if
 * includeEdges is true. The change is carried out using <cellsRemoved>.
 * This method fires <mxEvent.REMOVE_CELLS> while the transaction is in
 * progress. The removed cells are returned as an array.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to remove. If null is specified then the
 * selection cells which are deletable are used.
 * includeEdges - Optional boolean which specifies if all connected edges
 * should be removed as well. Default is true.
 */
mxGraph.prototype.removeCells = function(cells, includeEdges)
{
\tincludeEdges = (includeEdges != null) ? includeEdges : true;
\t
\tif (cells == null)
\t{
\t\tcells = this.getDeletableCells(this.getSelectionCells());
\t}

\t// Adds all edges to the cells
\tif (includeEdges)
\t{
\t\t// FIXME: Remove duplicate cells in result or do not add if
\t\t// in cells or descendant of cells
\t\tcells = this.getDeletableCells(this.addAllEdges(cells));
\t}
\telse
\t{
\t\tcells = cells.slice();
\t\t
\t\t// Removes edges that are currently not
\t\t// visible as those cannot be updated
\t\tvar edges = this.getDeletableCells(this.getAllEdges(cells));
\t\tvar dict = new mxDictionary();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tdict.put(cells[i], true);
\t\t}
\t\t
\t\tfor (var i = 0; i < edges.length; i++)
\t\t{
\t\t\tif (this.view.getState(edges[i]) == null &&
\t\t\t\t!dict.get(edges[i]))
\t\t\t{
\t\t\t\tdict.put(edges[i], true);
\t\t\t\tcells.push(edges[i]);
\t\t\t}
\t\t}
\t}

\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.cellsRemoved(cells);
\t\tthis.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS, 
\t\t\t\t'cells', cells, 'includeEdges', includeEdges));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}
\t
\treturn cells;
};

/**
 * Function: cellsRemoved
 * 
 * Removes the given cells from the model. This method fires
 * <mxEvent.CELLS_REMOVED> while the transaction is in progress.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to remove.
 */
mxGraph.prototype.cellsRemoved = function(cells)
{
\tif (cells != null && cells.length > 0)
\t{
\t\tvar scale = this.view.scale;
\t\tvar tr = this.view.translate;
\t\t
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\t// Creates hashtable for faster lookup
\t\t\tvar dict = new mxDictionary();
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tdict.put(cells[i], true);
\t\t\t}
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\t// Disconnects edges which are not being removed
\t\t\t\tvar edges = this.getAllEdges([cells[i]]);
\t\t\t\t
\t\t\t\tvar disconnectTerminal = mxUtils.bind(this, function(edge, source)
\t\t\t\t{
\t\t\t\t\tvar geo = this.model.getGeometry(edge);

\t\t\t\t\tif (geo != null)
\t\t\t\t\t{
\t\t\t\t\t\t// Checks if terminal is being removed
\t\t\t\t\t\tvar terminal = this.model.getTerminal(edge, source);
\t\t\t\t\t\tvar connected = false;
\t\t\t\t\t\tvar tmp = terminal;
\t\t\t\t\t\t
\t\t\t\t\t\twhile (tmp != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (cells[i] == tmp)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tconnected = true;
\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\ttmp = this.model.getParent(tmp);
\t\t\t\t\t\t}

\t\t\t\t\t\tif (connected)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\tvar state = this.view.getState(edge);

\t\t\t\t\t\t\tif (state != null && state.absolutePoints != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar pts = state.absolutePoints;
\t\t\t\t\t\t\t\tvar n = (source) ? 0 : pts.length - 1;

\t\t\t\t\t\t\t\tgeo.setTerminalPoint(new mxPoint(
\t\t\t\t\t\t\t\t\tpts[n].x / scale - tr.x - state.origin.x,
\t\t\t\t\t\t\t\t\tpts[n].y / scale - tr.y - state.origin.y), source);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t// Fallback to center of terminal if routing
\t\t\t\t\t\t\t\t// points are not available to add new point
\t\t\t\t\t\t\t\t// KNOWN: Should recurse to find parent offset
\t\t\t\t\t\t\t\t// of edge for nested groups but invisible edges
\t\t\t\t\t\t\t\t// should be removed in removeCells step
\t\t\t\t\t\t\t\tvar tstate = this.view.getState(terminal);
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (tstate != null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tgeo.setTerminalPoint(new mxPoint(
\t\t\t\t\t\t\t\t\t\ttstate.getCenterX() / scale - tr.x,
\t\t\t\t\t\t\t\t\t\ttstate.getCenterY() / scale - tr.y), source);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}

\t\t\t\t\t\t\tthis.model.setGeometry(edge, geo);
\t\t\t\t\t\t\tthis.model.setTerminal(edge, null, source);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\tfor (var j = 0; j < edges.length; j++)
\t\t\t\t{
\t\t\t\t\tif (!dict.get(edges[j]))
\t\t\t\t\t{
\t\t\t\t\t\tdict.put(edges[j], true);
\t\t\t\t\t\tdisconnectTerminal(edges[j], true);
\t\t\t\t\t\tdisconnectTerminal(edges[j], false);
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tthis.model.remove(cells[i]);
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_REMOVED, 'cells', cells));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: splitEdge
 * 
 * Splits the given edge by adding the newEdge between the previous source
 * and the given cell and reconnecting the source of the given edge to the
 * given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction
 * is in progress. Returns the new edge that was inserted.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to be splitted.
 * cells - <mxCells> that represents the cells to insert into the edge.
 * newEdge - <mxCell> that represents the edge to be inserted.
 * dx - Optional integer that specifies the vector to move the cells.
 * dy - Optional integer that specifies the vector to move the cells.
 * x - Integer that specifies the x-coordinate of the drop location.
 * y - Integer that specifies the y-coordinate of the drop location.
 * parent - Optional parent to insert the cell. If null the parent of
 * the edge is used.
 */
mxGraph.prototype.splitEdge = function(edge, cells, newEdge, dx, dy, x, y, parent)
{
\tdx = dx || 0;
\tdy = dy || 0;

\tparent = (parent != null) ? parent : this.model.getParent(edge);
\tvar source = this.model.getTerminal(edge, true);
\t
\tthis.model.beginUpdate();
\ttry
\t{
\t\tif (newEdge == null)
\t\t{
\t\t\tnewEdge = this.cloneCell(edge);
\t\t\t
\t\t\t// Removes waypoints before/after new cell
\t\t\tvar state = this.view.getState(edge);
\t\t\tvar geo = this.getCellGeometry(newEdge);
\t\t\t
\t\t\tif (geo != null && geo.points != null && state != null)
\t\t\t{
\t\t\t\tvar t = this.view.translate;
\t\t\t\tvar s = this.view.scale;
\t\t\t\tvar idx = mxUtils.findNearestSegment(state, (dx + t.x) * s, (dy + t.y) * s);
\t\t\t\tgeo.points = geo.points.slice(0, idx);
\t\t\t\t\t\t\t\t
\t\t\t\tgeo = this.getCellGeometry(edge);
\t\t\t\t
\t\t\t\tif (geo != null && geo.points != null)
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\tgeo.points = geo.points.slice(idx);
\t\t\t\t\tthis.model.setGeometry(edge, geo);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tthis.cellsMoved(cells, dx, dy, false, false);
\t\tthis.cellsAdded(cells, parent, this.model.getChildCount(parent), null, null,
\t\t\t\ttrue);
\t\tthis.cellsAdded([newEdge], parent, this.model.getChildCount(parent),
\t\t\t\tsource, cells[0], false);
\t\tthis.cellConnected(edge, cells[0], true);
\t\tthis.fireEvent(new mxEventObject(mxEvent.SPLIT_EDGE, 'edge', edge,
\t\t\t\t'cells', cells, 'newEdge', newEdge, 'dx', dx, 'dy', dy));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn newEdge;
};

/**
 * Group: Cell visibility
 */

/**
 * Function: toggleCells
 * 
 * Sets the visible state of the specified cells and all connected edges
 * if includeEdges is true. The change is carried out using <cellsToggled>.
 * This method fires <mxEvent.TOGGLE_CELLS> while the transaction is in
 * progress. Returns the cells whose visible state was changed.
 * 
 * Parameters:
 * 
 * show - Boolean that specifies the visible state to be assigned.
 * cells - Array of <mxCells> whose visible state should be changed. If
 * null is specified then the selection cells are used.
 * includeEdges - Optional boolean indicating if the visible state of all
 * connected edges should be changed as well. Default is true.
 */
mxGraph.prototype.toggleCells = function(show, cells, includeEdges)
{
\tif (cells == null)
\t{
\t\tcells = this.getSelectionCells();
\t}

\t// Adds all connected edges recursively
\tif (includeEdges)
\t{
\t\tcells = this.addAllEdges(cells);
\t}

\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.cellsToggled(cells, show);
\t\tthis.fireEvent(new mxEventObject(mxEvent.TOGGLE_CELLS,
\t\t\t'show', show, 'cells', cells, 'includeEdges', includeEdges));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: cellsToggled
 * 
 * Sets the visible state of the specified cells.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose visible state should be changed.
 * show - Boolean that specifies the visible state to be assigned.
 */
mxGraph.prototype.cellsToggled = function(cells, show)
{
\tif (cells != null && cells.length > 0)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tthis.model.setVisible(cells[i], show);
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Group: Folding
 */

/**
 * Function: foldCells
 * 
 * Sets the collapsed state of the specified cells and all descendants
 * if recurse is true. The change is carried out using <cellsFolded>.
 * This method fires <mxEvent.FOLD_CELLS> while the transaction is in
 * progress. Returns the cells whose collapsed state was changed.
 * 
 * Parameters:
 * 
 * collapsed - Boolean indicating the collapsed state to be assigned.
 * recurse - Optional boolean indicating if the collapsed state of all
 * descendants should be set. Default is false.
 * cells - Array of <mxCells> whose collapsed state should be set. If
 * null is specified then the foldable selection cells are used.
 * checkFoldable - Optional boolean indicating of isCellFoldable should be
 * checked. Default is false.
 * evt - Optional native event that triggered the invocation.
 */
mxGraph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable, evt)
{
\trecurse = (recurse != null) ? recurse : false;
\t
\tif (cells == null)
\t{
\t\tcells = this.getFoldableCells(this.getSelectionCells(), collapse);
\t}

\tthis.stopEditing(false);

\tthis.model.beginUpdate();
\ttry
\t{
\t\tthis.cellsFolded(cells, collapse, recurse, checkFoldable);
\t\tthis.fireEvent(new mxEventObject(mxEvent.FOLD_CELLS,
\t\t\t'collapse', collapse, 'recurse', recurse, 'cells', cells));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: cellsFolded
 * 
 * Sets the collapsed state of the specified cells. This method fires
 * <mxEvent.CELLS_FOLDED> while the transaction is in progress. Returns the
 * cells whose collapsed state was changed.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose collapsed state should be set.
 * collapsed - Boolean indicating the collapsed state to be assigned.
 * recurse - Boolean indicating if the collapsed state of all descendants
 * should be set.
 * checkFoldable - Optional boolean indicating of isCellFoldable should be
 * checked. Default is false.
 */
mxGraph.prototype.cellsFolded = function(cells, collapse, recurse, checkFoldable)
{
\tif (cells != null && cells.length > 0)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif ((!checkFoldable || this.isCellFoldable(cells[i], collapse)) &&
\t\t\t\t\tcollapse != this.isCellCollapsed(cells[i]))
\t\t\t\t{
\t\t\t\t\tthis.model.setCollapsed(cells[i], collapse);
\t\t\t\t\tthis.swapBounds(cells[i], collapse);

\t\t\t\t\tif (this.isExtendParent(cells[i]))
\t\t\t\t\t{
\t\t\t\t\t\tthis.extendParent(cells[i]);
\t\t\t\t\t}

\t\t\t\t\tif (recurse)
\t\t\t\t\t{
\t\t\t\t\t\tvar children = this.model.getChildren(cells[i]);
\t\t\t\t\t\tthis.cellsFolded(children, collapse, recurse);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tthis.constrainChild(cells[i]);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_FOLDED,
\t\t\t\t'cells', cells, 'collapse', collapse, 'recurse', recurse));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: swapBounds
 * 
 * Swaps the alternate and the actual bounds in the geometry of the given
 * cell invoking <updateAlternateBounds> before carrying out the swap.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the bounds should be swapped.
 * willCollapse - Boolean indicating if the cell is going to be collapsed.
 */
mxGraph.prototype.swapBounds = function(cell, willCollapse)
{
\tif (cell != null)
\t{
\t\tvar geo = this.model.getGeometry(cell);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tgeo = geo.clone();
\t\t\t
\t\t\tthis.updateAlternateBounds(cell, geo, willCollapse);
\t\t\tgeo.swap();
\t\t\t
\t\t\tthis.model.setGeometry(cell, geo);
\t\t}
\t}
};

/**
 * Function: updateAlternateBounds
 * 
 * Updates or sets the alternate bounds in the given geometry for the given
 * cell depending on whether the cell is going to be collapsed. If no
 * alternate bounds are defined in the geometry and
 * <collapseToPreferredSize> is true, then the preferred size is used for
 * the alternate bounds. The top, left corner is always kept at the same
 * location.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the geometry is being udpated.
 * g - <mxGeometry> for which the alternate bounds should be updated.
 * willCollapse - Boolean indicating if the cell is going to be collapsed.
 */
mxGraph.prototype.updateAlternateBounds = function(cell, geo, willCollapse)
{
\tif (cell != null && geo != null)
\t{
\t\tvar style = this.getCurrentCellStyle(cell);

\t\tif (geo.alternateBounds == null)
\t\t{
\t\t\tvar bounds = geo;
\t\t\t
\t\t\tif (this.collapseToPreferredSize)
\t\t\t{
\t\t\t\tvar tmp = this.getPreferredSizeForCell(cell);
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\tbounds = tmp;

\t\t\t\t\tvar startSize = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE);

\t\t\t\t\tif (startSize > 0)
\t\t\t\t\t{
\t\t\t\t\t\tbounds.height = Math.max(bounds.height, startSize);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tgeo.alternateBounds = new mxRectangle(0, 0, bounds.width, bounds.height);
\t\t}
\t\t
\t\tif (geo.alternateBounds != null)
\t\t{
\t\t\tgeo.alternateBounds.x = geo.x;
\t\t\tgeo.alternateBounds.y = geo.y;
\t\t\t
\t\t\tvar alpha = mxUtils.toRadians(style[mxConstants.STYLE_ROTATION] || 0);
\t\t\t
\t\t\tif (alpha != 0)
\t\t\t{
\t\t\t\tvar dx = geo.alternateBounds.getCenterX() - geo.getCenterX();
\t\t\t\tvar dy = geo.alternateBounds.getCenterY() - geo.getCenterY();
\t
\t\t\t\tvar cos = Math.cos(alpha);
\t\t\t\tvar sin = Math.sin(alpha);
\t
\t\t\t\tvar dx2 = cos * dx - sin * dy;
\t\t\t\tvar dy2 = sin * dx + cos * dy;
\t\t\t\t
\t\t\t\tgeo.alternateBounds.x += dx2 - dx;
\t\t\t\tgeo.alternateBounds.y += dy2 - dy;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: addAllEdges
 * 
 * Returns an array with the given cells and all edges that are connected
 * to a cell or one of its descendants.
 */
mxGraph.prototype.addAllEdges = function(cells)
{
\tvar allCells = cells.slice();
\t
\treturn mxUtils.removeDuplicates(allCells.concat(this.getAllEdges(cells)));
};

/**
 * Function: getAllEdges
 * 
 * Returns all edges connected to the given cells or its descendants.
 */
mxGraph.prototype.getAllEdges = function(cells)
{
\tvar edges = [];
\t
\tif (cells != null)
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar edgeCount = this.model.getEdgeCount(cells[i]);
\t\t\t
\t\t\tfor (var j = 0; j < edgeCount; j++)
\t\t\t{
\t\t\t\tedges.push(this.model.getEdgeAt(cells[i], j));
\t\t\t}

\t\t\t// Recurses
\t\t\tvar children = this.model.getChildren(cells[i]);
\t\t\tedges = edges.concat(this.getAllEdges(children));
\t\t}
\t}
\t
\treturn edges;
};

/**
 * Group: Cell sizing
 */

/**
 * Function: updateCellSize
 * 
 * Updates the size of the given cell in the model using <cellSizeUpdated>.
 * This method fires <mxEvent.UPDATE_CELL_SIZE> while the transaction is in
 * progress. Returns the cell whose size was updated.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose size should be updated.
 */
mxGraph.prototype.updateCellSize = function(cell, ignoreChildren)
{
\tignoreChildren = (ignoreChildren != null) ? ignoreChildren : false;
\t
\tthis.model.beginUpdate();\t\t\t\t
\ttry
\t{
\t\tthis.cellSizeUpdated(cell, ignoreChildren);
\t\tthis.fireEvent(new mxEventObject(mxEvent.UPDATE_CELL_SIZE,
\t\t\t\t'cell', cell, 'ignoreChildren', ignoreChildren));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}
\t
\treturn cell;
};

/**
 * Function: cellSizeUpdated
 * 
 * Updates the size of the given cell in the model using
 * <getPreferredSizeForCell> to get the new size.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the size should be changed.
 */
mxGraph.prototype.cellSizeUpdated = function(cell, ignoreChildren)
{
\tif (cell != null)
\t{
\t\tthis.model.beginUpdate();\t\t\t\t
\t\ttry
\t\t{
\t\t\tvar size = this.getPreferredSizeForCell(cell);
\t\t\tvar geo = this.model.getGeometry(cell);
\t\t\t
\t\t\tif (size != null && geo != null)
\t\t\t{
\t\t\t\tvar collapsed = this.isCellCollapsed(cell);
\t\t\t\tgeo = geo.clone();

\t\t\t\tif (this.isSwimlane(cell))
\t\t\t\t{
\t\t\t\t\tvar style = this.getCellStyle(cell);
\t\t\t\t\tvar cellStyle = this.model.getStyle(cell);

\t\t\t\t\tif (cellStyle == null)
\t\t\t\t\t{
\t\t\t\t\t\tcellStyle = '';
\t\t\t\t\t}

\t\t\t\t\tif (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
\t\t\t\t\t{
\t\t\t\t\t\tcellStyle = mxUtils.setStyle(cellStyle,
\t\t\t\t\t\t\t\tmxConstants.STYLE_STARTSIZE, size.height + 8);

\t\t\t\t\t\tif (collapsed)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.height = size.height + 8;
\t\t\t\t\t\t}

\t\t\t\t\t\tgeo.width = size.width;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tcellStyle = mxUtils.setStyle(cellStyle,
\t\t\t\t\t\t\t\tmxConstants.STYLE_STARTSIZE, size.width + 8);

\t\t\t\t\t\tif (collapsed)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.width = size.width + 8;
\t\t\t\t\t\t}

\t\t\t\t\t\tgeo.height = size.height;
\t\t\t\t\t}

\t\t\t\t\tthis.model.setStyle(cell, cellStyle);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar state = this.view.createState(cell);
\t\t\t\t\tvar align = (state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER);
\t\t\t\t\t
\t\t\t\t\tif (align == mxConstants.ALIGN_RIGHT)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.x += geo.width - size.width;
\t\t\t\t\t}
\t\t\t\t\telse if (align == mxConstants.ALIGN_CENTER)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.x += Math.round((geo.width - size.width) / 2);
\t\t\t\t\t}

\t\t\t\t\tvar valign = this.getVerticalAlign(state);
\t\t\t\t\t
\t\t\t\t\tif (valign == mxConstants.ALIGN_BOTTOM)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.y += geo.height - size.height;
\t\t\t\t\t}
\t\t\t\t\telse if (valign == mxConstants.ALIGN_MIDDLE)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.y += Math.round((geo.height - size.height) / 2);
\t\t\t\t\t}

\t\t\t\t\tgeo.width = size.width;
\t\t\t\t\tgeo.height = size.height;
\t\t\t\t}

\t\t\t\tif (!ignoreChildren && !collapsed)
\t\t\t\t{
\t\t\t\t\tvar bounds = this.view.getBounds(this.model.getChildren(cell));

\t\t\t\t\tif (bounds != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar tr = this.view.translate;
\t\t\t\t\t\tvar scale = this.view.scale;

\t\t\t\t\t\tvar width = (bounds.x + bounds.width) / scale - geo.x - tr.x;
\t\t\t\t\t\tvar height = (bounds.y + bounds.height) / scale - geo.y - tr.y;

\t\t\t\t\t\tgeo.width = Math.max(geo.width, width);
\t\t\t\t\t\tgeo.height = Math.max(geo.height, height);
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tthis.cellsResized([cell], [geo], false);
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: getPreferredSizeForCell
 * 
 * Returns the preferred width and height of the given <mxCell> as an
 * <mxRectangle>. To implement a minimum width, add a new style eg.
 * minWidth in the vertex and override this method as follows.
 * 
 * (code)
 * var graphGetPreferredSizeForCell = graph.getPreferredSizeForCell;
 * graph.getPreferredSizeForCell = function(cell)
 * {
 *   var result = graphGetPreferredSizeForCell.apply(this, arguments);
 *   var style = this.getCellStyle(cell);
 *   
 *   if (style['minWidth'] > 0)
 *   {
 *     result.width = Math.max(style['minWidth'], result.width);
 *   }
 * 
 *   return result;
 * };
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the preferred size should be returned.
 * textWidth - Optional maximum text width for word wrapping.
 */
mxGraph.prototype.getPreferredSizeForCell = function(cell, textWidth)
{
\tvar result = null;
\t
\tif (cell != null)
\t{
\t\tvar state = this.view.createState(cell);
\t\tvar style = state.style;

\t\tif (!this.model.isEdge(cell))
\t\t{
\t\t\tvar fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
\t\t\tvar dx = 0;
\t\t\tvar dy = 0;
\t\t\t
\t\t\t// Adds dimension of image if shape is a label
\t\t\tif (this.getImage(state) != null || style[mxConstants.STYLE_IMAGE] != null)
\t\t\t{
\t\t\t\tif (style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_LABEL)
\t\t\t\t{
\t\t\t\t\tif (style[mxConstants.STYLE_VERTICAL_ALIGN] == mxConstants.ALIGN_MIDDLE)
\t\t\t\t\t{
\t\t\t\t\t\tdx += parseFloat(style[mxConstants.STYLE_IMAGE_WIDTH]) || mxLabel.prototype.imageSize;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (style[mxConstants.STYLE_ALIGN] != mxConstants.ALIGN_CENTER)
\t\t\t\t\t{
\t\t\t\t\t\tdy += parseFloat(style[mxConstants.STYLE_IMAGE_HEIGHT]) || mxLabel.prototype.imageSize;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// Adds spacings
\t\t\tdx += 2 * (style[mxConstants.STYLE_SPACING] || 0);
\t\t\tdx += style[mxConstants.STYLE_SPACING_LEFT] || 0;
\t\t\tdx += style[mxConstants.STYLE_SPACING_RIGHT] || 0;

\t\t\tdy += 2 * (style[mxConstants.STYLE_SPACING] || 0);
\t\t\tdy += style[mxConstants.STYLE_SPACING_TOP] || 0;
\t\t\tdy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0;
\t\t\t
\t\t\t// Add spacing for collapse/expand icon
\t\t\t// LATER: Check alignment and use constants
\t\t\t// for image spacing
\t\t\tvar image = this.getFoldingImage(state);
\t\t\t
\t\t\tif (image != null)
\t\t\t{
\t\t\t\tdx += image.width + 8;
\t\t\t}

\t\t\t// Adds space for label
\t\t\tvar value = this.cellRenderer.getLabelValue(state);

\t\t\tif (value != null && value.length > 0)
\t\t\t{
\t\t\t\tif (!this.isHtmlLabel(state.cell))
\t\t\t\t{
\t\t\t\t\tvalue = mxUtils.htmlEntities(value, false);
\t\t\t\t}
\t\t\t\t
\t\t\t\tvalue = value.replace(/\\n/g, '<br>');
\t\t\t\t
\t\t\t\tvar size = mxUtils.getSizeForString(value, fontSize,
\t\t\t\t\tstyle[mxConstants.STYLE_FONTFAMILY], textWidth,
\t\t\t\t\tstyle[mxConstants.STYLE_FONTSTYLE]);
\t\t\t\tvar width = size.width + dx;
\t\t\t\tvar height = size.height + dy;
\t\t\t\t
\t\t\t\tif (!mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
\t\t\t\t{
\t\t\t\t\tvar tmp = height;
\t\t\t\t\t
\t\t\t\t\theight = width;
\t\t\t\t\twidth = tmp;
\t\t\t\t}
\t\t\t
\t\t\t\tif (this.gridEnabled)
\t\t\t\t{
\t\t\t\t\twidth = this.snap(width + this.gridSize / 2);
\t\t\t\t\theight = this.snap(height + this.gridSize / 2);
\t\t\t\t}

\t\t\t\tresult = new mxRectangle(0, 0, width, height);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar gs2 = 4 * this.gridSize;
\t\t\t\tresult = new mxRectangle(0, 0, gs2, gs2);
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: resizeCell
 * 
 * Sets the bounds of the given cell using <resizeCells>. Returns the
 * cell which was passed to the function.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose bounds should be changed.
 * bounds - <mxRectangle> that represents the new bounds.
 */
mxGraph.prototype.resizeCell = function(cell, bounds, recurse)
{
\treturn this.resizeCells([cell], [bounds], recurse)[0];
};

/**
 * Function: resizeCells
 * 
 * Sets the bounds of the given cells and fires a <mxEvent.RESIZE_CELLS>
 * event while the transaction is in progress. Returns the cells which
 * have been passed to the function.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose bounds should be changed.
 * bounds - Array of <mxRectangles> that represent the new bounds.
 */
mxGraph.prototype.resizeCells = function(cells, bounds, recurse)
{
\trecurse = (recurse != null) ? recurse : this.isRecursiveResize();
\t
\tthis.model.beginUpdate();
\ttry
\t{
\t\tvar prev = this.cellsResized(cells, bounds, recurse);
\t\tthis.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS,
\t\t\t'cells', cells, 'bounds', bounds, 'previous', prev));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn cells;
};

/**
 * Function: cellsResized
 * 
 * Sets the bounds of the given cells and fires a <mxEvent.CELLS_RESIZED>
 * event. If <extendParents> is true, then the parent is extended if a
 * child size is changed so that it overlaps with the parent.
 * 
 * The following example shows how to control group resizes to make sure
 * that all child cells stay within the group.
 * 
 * (code)
 * graph.addListener(mxEvent.CELLS_RESIZED, function(sender, evt)
 * {
 *   var cells = evt.getProperty('cells');
 *   
 *   if (cells != null)
 *   {
 *     for (var i = 0; i < cells.length; i++)
 *     {
 *       if (graph.getModel().getChildCount(cells[i]) > 0)
 *       {
 *         var geo = graph.getCellGeometry(cells[i]);
 *         
 *         if (geo != null)
 *         {
 *           var children = graph.getChildCells(cells[i], true, true);
 *           var bounds = graph.getBoundingBoxFromGeometry(children, true);
 *           
 *           geo = geo.clone();
 *           geo.width = Math.max(geo.width, bounds.width);
 *           geo.height = Math.max(geo.height, bounds.height);
 *           
 *           graph.getModel().setGeometry(cells[i], geo);
 *         }
 *       }
 *     }
 *   }
 * });
 * (end)
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose bounds should be changed.
 * bounds - Array of <mxRectangles> that represent the new bounds.
 * recurse - Optional boolean that specifies if the children should be resized.
 */
mxGraph.prototype.cellsResized = function(cells, bounds, recurse)
{
\trecurse = (recurse != null) ? recurse : false;
\tvar prev = [];

\tif (cells != null && bounds != null && cells.length == bounds.length)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tprev.push(this.cellResized(cells[i], bounds[i], false, recurse));

\t\t\t\tif (this.isExtendParent(cells[i]))
\t\t\t\t{
\t\t\t\t\tthis.extendParent(cells[i]);
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.constrainChild(cells[i]);
\t\t\t}

\t\t\tif (this.resetEdgesOnResize)
\t\t\t{
\t\t\t\tthis.resetEdges(cells);
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_RESIZED,
\t\t\t\t'cells', cells, 'bounds', bounds, 'previous', prev));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
\t
\treturn prev;
};

/**
 * Function: cellResized
 * 
 * Resizes the parents recursively so that they contain the complete area
 * of the resized child cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose bounds should be changed.
 * bounds - <mxRectangles> that represent the new bounds.
 * ignoreRelative - Boolean that indicates if relative cells should be ignored.
 * recurse - Optional boolean that specifies if the children should be resized.
 */
mxGraph.prototype.cellResized = function(cell, bounds, ignoreRelative, recurse)
{
\tvar prev = this.model.getGeometry(cell);

\tif (prev != null && (prev.x != bounds.x || prev.y != bounds.y ||
\t\tprev.width != bounds.width || prev.height != bounds.height))
\t{
\t\tvar geo = prev.clone();

\t\tif (!ignoreRelative && geo.relative)
\t\t{
\t\t\tvar offset = geo.offset;

\t\t\tif (offset != null)
\t\t\t{
\t\t\t\toffset.x += bounds.x - geo.x;
\t\t\t\toffset.y += bounds.y - geo.y;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tgeo.x = bounds.x;
\t\t\tgeo.y = bounds.y;
\t\t}

\t\tgeo.width = bounds.width;
\t\tgeo.height = bounds.height;

\t\tif (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
\t\t{
\t\t\tgeo.x = Math.max(0, geo.x);
\t\t\tgeo.y = Math.max(0, geo.y);
\t\t}

\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tif (recurse)
\t\t\t{
\t\t\t\tthis.resizeChildCells(cell, geo);
\t\t\t}
\t\t\t\t\t\t
\t\t\tthis.model.setGeometry(cell, geo);
\t\t\tthis.constrainChildCells(cell);
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
\t
\treturn prev;
};

/**
 * Function: resizeChildCells
 * 
 * Resizes the child cells of the given cell for the given new geometry with
 * respect to the current geometry of the cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that has been resized.
 * newGeo - <mxGeometry> that represents the new bounds.
 */
mxGraph.prototype.resizeChildCells = function(cell, newGeo)
{
\tvar geo = this.model.getGeometry(cell);
\tvar dx = (geo.width != 0) ? newGeo.width / geo.width : 1;
\tvar dy = (geo.height != 0) ? newGeo.height / geo.height : 1;
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tthis.scaleCell(this.model.getChildAt(cell, i), dx, dy, true);
\t}
};

/**
 * Function: constrainChildCells
 * 
 * Constrains the children of the given cell using <constrainChild>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that has been resized.
 */
mxGraph.prototype.constrainChildCells = function(cell)
{
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tthis.constrainChild(this.model.getChildAt(cell, i));
\t}
};

/**
 * Function: scaleCell
 * 
 * Scales the points, position and size of the given cell according to the
 * given vertical and horizontal scaling factors.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose geometry should be scaled.
 * dx - Horizontal scaling factor.
 * dy - Vertical scaling factor.
 * recurse - Boolean indicating if the child cells should be scaled.
 */
mxGraph.prototype.scaleCell = function(cell, dx, dy, recurse)
{
\tvar geo = this.model.getGeometry(cell);
\t
\tif (geo != null)
\t{
\t\tvar style = this.getCurrentCellStyle(cell);
\t\tgeo = geo.clone();
\t\t
\t\t// Stores values for restoring based on style
\t\tvar x = geo.x;
\t\tvar y = geo.y
\t\tvar w = geo.width;
\t\tvar h = geo.height;
\t\t
\t\tgeo.scale(dx, dy, style[mxConstants.STYLE_ASPECT] == 'fixed');
\t\t
\t\tif (style[mxConstants.STYLE_RESIZE_WIDTH] == '1')
\t\t{
\t\t\tgeo.width = w * dx;
\t\t}
\t\telse if (style[mxConstants.STYLE_RESIZE_WIDTH] == '0')
\t\t{
\t\t\tgeo.width = w;
\t\t}
\t\t
\t\tif (style[mxConstants.STYLE_RESIZE_HEIGHT] == '1')
\t\t{
\t\t\tgeo.height = h * dy;
\t\t}
\t\telse if (style[mxConstants.STYLE_RESIZE_HEIGHT] == '0')
\t\t{
\t\t\tgeo.height = h;
\t\t}
\t\t
\t\tif (!this.isCellMovable(cell))
\t\t{
\t\t\tgeo.x = x;
\t\t\tgeo.y = y;
\t\t}
\t\t
\t\tif (!this.isCellResizable(cell))
\t\t{
\t\t\tgeo.width = w;
\t\t\tgeo.height = h;
\t\t}

\t\tif (this.model.isVertex(cell))
\t\t{
\t\t\tthis.cellResized(cell, geo, true, recurse);
\t\t}
\t\telse
\t\t{
\t\t\tthis.model.setGeometry(cell, geo);
\t\t}
\t}
};

/**
 * Function: extendParent
 * 
 * Resizes the parents recursively so that they contain the complete area
 * of the resized child cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that has been resized.
 */
mxGraph.prototype.extendParent = function(cell)
{
\tif (cell != null)
\t{
\t\tvar parent = this.model.getParent(cell);
\t\tvar p = this.getCellGeometry(parent);
\t\t
\t\tif (parent != null && p != null && !this.isCellCollapsed(parent))
\t\t{
\t\t\tvar geo = this.getCellGeometry(cell);
\t\t\t
\t\t\tif (geo != null && !geo.relative &&
\t\t\t\t(p.width < geo.x + geo.width ||
\t\t\t\tp.height < geo.y + geo.height))
\t\t\t{
\t\t\t\tp = p.clone();
\t\t\t\t
\t\t\t\tp.width = Math.max(p.width, geo.x + geo.width);
\t\t\t\tp.height = Math.max(p.height, geo.y + geo.height);
\t\t\t\t
\t\t\t\tthis.cellsResized([parent], [p], false);
\t\t\t}
\t\t}
\t}
};

/**
 * Group: Cell moving
 */

/**
 * Function: importCells
 * 
 * Clones and inserts the given cells into the graph using the move
 * method and returns the inserted cells. This shortcut is used if
 * cells are inserted via datatransfer.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be imported.
 * dx - Integer that specifies the x-coordinate of the vector. Default is 0.
 * dy - Integer that specifies the y-coordinate of the vector. Default is 0.
 * target - <mxCell> that represents the new parent of the cells.
 * evt - Mouseevent that triggered the invocation.
 * mapping - Optional mapping for existing clones.
 */
mxGraph.prototype.importCells = function(cells, dx, dy, target, evt, mapping)
{\t
\treturn this.moveCells(cells, dx, dy, true, target, evt, mapping);
};

/**
 * Function: moveCells
 * 
 * Moves or clones the specified cells and moves the cells or clones by the
 * given amount, adding them to the optional target cell. The evt is the
 * mouse event as the mouse was released. The change is carried out using
 * <cellsMoved>. This method fires <mxEvent.MOVE_CELLS> while the
 * transaction is in progress. Returns the cells that were moved.
 * 
 * Use the following code to move all cells in the graph.
 * 
 * (code)
 * graph.moveCells(graph.getChildCells(null, true, true), 10, 10);
 * (end)
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be moved, cloned or added to the target.
 * dx - Integer that specifies the x-coordinate of the vector. Default is 0.
 * dy - Integer that specifies the y-coordinate of the vector. Default is 0.
 * clone - Boolean indicating if the cells should be cloned. Default is false.
 * target - <mxCell> that represents the new parent of the cells.
 * evt - Mouseevent that triggered the invocation.
 * mapping - Optional mapping for existing clones.
 */
mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt, mapping)
{
\tdx = (dx != null) ? dx : 0;
\tdy = (dy != null) ? dy : 0;
\tclone = (clone != null) ? clone : false;
\t
\tif (cells != null && (dx != 0 || dy != 0 || clone || target != null))
\t{
\t\t// Removes descendants with ancestors in cells to avoid multiple moving
\t\tcells = this.model.getTopmostCells(cells);
\t\tvar origCells = cells;
\t\t
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\t// Faster cell lookups to remove relative edge labels with selected
\t\t\t// terminals to avoid explicit and implicit move at same time
\t\t\tvar dict = new mxDictionary();
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tdict.put(cells[i], true);
\t\t\t}
\t\t\t
\t\t\tvar isSelected = mxUtils.bind(this, function(cell)
\t\t\t{
\t\t\t\twhile (cell != null)
\t\t\t\t{
\t\t\t\t\tif (dict.get(cell))
\t\t\t\t\t{
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tcell = this.model.getParent(cell);
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn false;
\t\t\t});
\t\t\t
\t\t\t// Removes relative edge labels with selected terminals
\t\t\tvar checked = [];
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar geo = this.getCellGeometry(cells[i]);
\t\t\t\tvar parent = this.model.getParent(cells[i]);
\t\t
\t\t\t\tif ((geo == null || !geo.relative) || !this.model.isEdge(parent) ||
\t\t\t\t\t(!isSelected(this.model.getTerminal(parent, true)) &&
\t\t\t\t\t!isSelected(this.model.getTerminal(parent, false))))
\t\t\t\t{
\t\t\t\t\tchecked.push(cells[i]);
\t\t\t\t}
\t\t\t}

\t\t\tcells = checked;
\t\t\t
\t\t\tif (clone)
\t\t\t{
\t\t\t\tcells = this.cloneCells(cells, this.isCloneInvalidEdges(), mapping);

\t\t\t\tif (target == null)
\t\t\t\t{
\t\t\t\t\ttarget = this.getDefaultParent();
\t\t\t\t}
\t\t\t}

\t\t\t// FIXME: Cells should always be inserted first before any other edit
\t\t\t// to avoid forward references in sessions.
\t\t\t// Need to disable allowNegativeCoordinates if target not null to
\t\t\t// allow for temporary negative numbers until cellsAdded is called.
\t\t\tvar previous = this.isAllowNegativeCoordinates();
\t\t\t
\t\t\tif (target != null)
\t\t\t{
\t\t\t\tthis.setAllowNegativeCoordinates(true);
\t\t\t}
\t\t\t
\t\t\tthis.cellsMoved(cells, dx, dy, !clone && this.isDisconnectOnMove()
\t\t\t\t\t&& this.isAllowDanglingEdges(), target == null,
\t\t\t\t\tthis.isExtendParentsOnMove() && target == null);
\t\t\t
\t\t\tthis.setAllowNegativeCoordinates(previous);

\t\t\tif (target != null)
\t\t\t{
\t\t\t\tvar index = this.model.getChildCount(target);
\t\t\t\tthis.cellsAdded(cells, target, index, null, null, true);
\t\t\t\t
\t\t\t\t// Restores parent edge on cloned edge labels
\t\t\t\tif (clone)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar geo = this.getCellGeometry(cells[i]);
\t\t\t\t\t\tvar parent = this.model.getParent(origCells[i]);
\t\t\t\t\t\t
\t\t\t\t\t\tif (geo != null && geo.relative &&
\t\t\t\t\t\t\tthis.model.isEdge(parent) &&
\t\t\t\t\t\t\tthis.model.contains(parent))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.model.add(parent, cells[i]);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// Dispatches a move event
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.MOVE_CELLS, 'cells', cells,
\t\t\t\t'dx', dx, 'dy', dy, 'clone', clone, 'target', target, 'event', evt));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}

\treturn cells;
};

/**
 * Function: cellsMoved
 * 
 * Moves the specified cells by the given vector, disconnecting the cells
 * using disconnectGraph is disconnect is true. This method fires
 * <mxEvent.CELLS_MOVED> while the transaction is in progress.
 */
mxGraph.prototype.cellsMoved = function(cells, dx, dy, disconnect, constrain, extend)
{
\tif (cells != null && (dx != 0 || dy != 0))
\t{
\t\textend = (extend != null) ? extend : false;

\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tif (disconnect)
\t\t\t{
\t\t\t\tthis.disconnectGraph(cells);
\t\t\t}

\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tthis.translateCell(cells[i], dx, dy);
\t\t\t\t
\t\t\t\tif (extend && this.isExtendParent(cells[i]))
\t\t\t\t{
\t\t\t\t\tthis.extendParent(cells[i]);
\t\t\t\t}
\t\t\t\telse if (constrain)
\t\t\t\t{
\t\t\t\t\tthis.constrainChild(cells[i]);
\t\t\t\t}
\t\t\t}

\t\t\tif (this.resetEdgesOnMove)
\t\t\t{
\t\t\t\tthis.resetEdges(cells);
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELLS_MOVED,
\t\t\t\t'cells', cells, 'dx', dx, 'dy', dy, 'disconnect', disconnect));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: translateCell
 * 
 * Translates the geometry of the given cell and stores the new,
 * translated geometry in the model as an atomic change.
 */
mxGraph.prototype.translateCell = function(cell, dx, dy)
{
\tvar geo = this.model.getGeometry(cell);

\tif (geo != null)
\t{
\t\tdx = parseFloat(dx);
\t\tdy = parseFloat(dy);
\t\tgeo = geo.clone();
\t\tgeo.translate(dx, dy);

\t\tif (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
\t\t{
\t\t\tgeo.x = Math.max(0, parseFloat(geo.x));
\t\t\tgeo.y = Math.max(0, parseFloat(geo.y));
\t\t}
\t\t
\t\tif (geo.relative && !this.model.isEdge(cell))
\t\t{
\t\t\tvar parent = this.model.getParent(cell);
\t\t\tvar angle = 0;
\t\t\t
\t\t\tif (this.model.isVertex(parent))
\t\t\t{
\t\t\t\tvar style = this.getCurrentCellStyle(parent);
\t\t\t\tangle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
\t\t\t}
\t\t\t
\t\t\tif (angle != 0)
\t\t\t{
\t\t\t\tvar rad = mxUtils.toRadians(-angle);
\t\t\t\tvar cos = Math.cos(rad);
\t\t\t\tvar sin = Math.sin(rad);
\t\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(dx, dy), cos, sin, new mxPoint(0, 0));
\t\t\t\tdx = pt.x;
\t\t\t\tdy = pt.y;
\t\t\t}
\t\t\t
\t\t\tif (geo.offset == null)
\t\t\t{
\t\t\t\tgeo.offset = new mxPoint(dx, dy);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tgeo.offset.x = parseFloat(geo.offset.x) + dx;
\t\t\t\tgeo.offset.y = parseFloat(geo.offset.y) + dy;
\t\t\t}
\t\t}

\t\tthis.model.setGeometry(cell, geo);
\t}
};

/**
 * Function: getCellContainmentArea
 * 
 * Returns the <mxRectangle> inside which a cell is to be kept.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the area should be returned.
 */
mxGraph.prototype.getCellContainmentArea = function(cell)
{
\tif (cell != null && !this.model.isEdge(cell))
\t{
\t\tvar parent = this.model.getParent(cell);
\t\t
\t\tif (parent != null && parent != this.getDefaultParent())
\t\t{
\t\t\tvar g = this.model.getGeometry(parent);
\t\t\t
\t\t\tif (g != null)
\t\t\t{
\t\t\t\tvar x = 0;
\t\t\t\tvar y = 0;
\t\t\t\tvar w = g.width;
\t\t\t\tvar h = g.height;
\t\t\t\t
\t\t\t\tif (this.isSwimlane(parent))
\t\t\t\t{
\t\t\t\t\tvar size = this.getStartSize(parent);
\t\t\t\t\tvar style = this.getCurrentCellStyle(parent);
\t\t\t\t\tvar dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
\t\t\t\t\tvar flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
\t\t\t\t\tvar flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
\t\t\t\t\t
\t\t\t\t\tif (dir == mxConstants.DIRECTION_SOUTH || dir == mxConstants.DIRECTION_NORTH)
\t\t\t\t\t{
\t\t\t\t\t\tvar tmp = size.width;
\t\t\t\t\t\tsize.width = size.height;
\t\t\t\t\t\tsize.height = tmp;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif ((dir == mxConstants.DIRECTION_EAST && !flipV) || (dir == mxConstants.DIRECTION_NORTH && !flipH) ||
\t\t\t\t\t\t(dir == mxConstants.DIRECTION_WEST && flipV) || (dir == mxConstants.DIRECTION_SOUTH && flipH))
\t\t\t\t\t{
\t\t\t\t\t\tx = size.width;
\t\t\t\t\t\ty = size.height;
\t\t\t\t\t}

\t\t\t\t\tw -= size.width;
\t\t\t\t\th -= size.height;
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn new mxRectangle(x, y, w, h);
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: getMaximumGraphBounds
 * 
 * Returns the bounds inside which the diagram should be kept as an
 * <mxRectangle>.
 */
mxGraph.prototype.getMaximumGraphBounds = function()
{
\treturn this.maximumGraphBounds;
};

/**
 * Function: constrainChild
 * 
 * Keeps the given cell inside the bounds returned by
 * <getCellContainmentArea> for its parent, according to the rules defined by
 * <getOverlap> and <isConstrainChild>. This modifies the cell's geometry
 * in-place and does not clone it.
 * 
 * Parameters:
 * 
 * cells - <mxCell> which should be constrained.
 * sizeFirst - Specifies if the size should be changed first. Default is true.
 */
mxGraph.prototype.constrainChild = function(cell, sizeFirst)
{
\tsizeFirst = (sizeFirst != null) ? sizeFirst : true;
\t
\tif (cell != null)
\t{
\t\tvar geo = this.getCellGeometry(cell);
\t\t
\t\tif (geo != null && (this.isConstrainRelativeChildren() || !geo.relative))
\t\t{
\t\t\tvar parent = this.model.getParent(cell);
\t\t\tvar pgeo = this.getCellGeometry(parent);
\t\t\tvar max = this.getMaximumGraphBounds();
\t\t\t
\t\t\t// Finds parent offset
\t\t\tif (max != null)
\t\t\t{
\t\t\t\tvar off = this.getBoundingBoxFromGeometry([parent], false);
\t\t\t\t
\t\t\t\tif (off != null)
\t\t\t\t{
\t\t\t\t\tmax = mxRectangle.fromRectangle(max);
\t\t\t\t\t
\t\t\t\t\tmax.x -= off.x;
\t\t\t\t\tmax.y -= off.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (this.isConstrainChild(cell))
\t\t\t{
\t\t\t\tvar tmp = this.getCellContainmentArea(cell);
\t\t\t\t
\t\t\t\tif (tmp != null)
\t\t\t\t{
\t\t\t\t\tvar overlap = this.getOverlap(cell);
\t
\t\t\t\t\tif (overlap > 0)
\t\t\t\t\t{
\t\t\t\t\t\ttmp = mxRectangle.fromRectangle(tmp);
\t\t\t\t\t\t
\t\t\t\t\t\ttmp.x -= tmp.width * overlap;
\t\t\t\t\t\ttmp.y -= tmp.height * overlap;
\t\t\t\t\t\ttmp.width += 2 * tmp.width * overlap;
\t\t\t\t\t\ttmp.height += 2 * tmp.height * overlap;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Find the intersection between max and tmp
\t\t\t\t\tif (max == null)
\t\t\t\t\t{
\t\t\t\t\t\tmax = tmp;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tmax = mxRectangle.fromRectangle(max);
\t\t\t\t\t\tmax.intersect(tmp);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (max != null)
\t\t\t{
\t\t\t\tvar cells = [cell];
\t\t\t\t
\t\t\t\tif (!this.isCellCollapsed(cell))
\t\t\t\t{
\t\t\t\t\tvar desc = this.model.getDescendants(cell);
\t\t\t\t\t
\t\t\t\t\tfor (var i = 0; i < desc.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tif (this.isCellVisible(desc[i]))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcells.push(desc[i]);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar bbox = this.getBoundingBoxFromGeometry(cells, false);
\t\t\t\t
\t\t\t\tif (bbox != null)
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t
\t\t\t\t\t// Cumulative horizontal movement
\t\t\t\t\tvar dx = 0;
\t\t\t\t\t
\t\t\t\t\tif (geo.width > max.width)
\t\t\t\t\t{
\t\t\t\t\t\tdx = geo.width - max.width;
\t\t\t\t\t\tgeo.width -= dx;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (bbox.x + bbox.width > max.x + max.width)
\t\t\t\t\t{
\t\t\t\t\t\tdx -= bbox.x + bbox.width - max.x - max.width - dx;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Cumulative vertical movement
\t\t\t\t\tvar dy = 0;
\t\t\t\t\t
\t\t\t\t\tif (geo.height > max.height)
\t\t\t\t\t{
\t\t\t\t\t\tdy = geo.height - max.height;
\t\t\t\t\t\tgeo.height -= dy;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (bbox.y + bbox.height > max.y + max.height)
\t\t\t\t\t{
\t\t\t\t\t\tdy -= bbox.y + bbox.height - max.y - max.height - dy;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (bbox.x < max.x)
\t\t\t\t\t{
\t\t\t\t\t\tdx -= bbox.x - max.x;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (bbox.y < max.y)
\t\t\t\t\t{
\t\t\t\t\t\tdy -= bbox.y - max.y;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (dx != 0 || dy != 0)
\t\t\t\t\t{
\t\t\t\t\t\tif (geo.relative)
\t\t\t\t\t\t{
\t\t\t\t\t\t\t// Relative geometries are moved via absolute offset
\t\t\t\t\t\t\tif (geo.offset == null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo.offset = new mxPoint();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t\tgeo.offset.x += dx;
\t\t\t\t\t\t\tgeo.offset.y += dy;
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo.x += dx;
\t\t\t\t\t\t\tgeo.y += dy;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tthis.model.setGeometry(cell, geo);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: resetEdges
 * 
 * Resets the control points of the edges that are connected to the given
 * cells if not both ends of the edge are in the given cells array.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> for which the connected edges should be
 * reset.
 */
mxGraph.prototype.resetEdges = function(cells)
{
\tif (cells != null)
\t{
\t\t// Prepares faster cells lookup
\t\tvar dict = new mxDictionary();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tdict.put(cells[i], true);
\t\t}
\t\t
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar edges = this.model.getEdges(cells[i]);
\t\t\t\t
\t\t\t\tif (edges != null)
\t\t\t\t{
\t\t\t\t\tfor (var j = 0; j < edges.length; j++)
\t\t\t\t\t{
\t\t\t\t\t\tvar state = this.view.getState(edges[j]);
\t\t\t\t\t\t
\t\t\t\t\t\tvar source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[j], true);
\t\t\t\t\t\tvar target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[j], false);
\t\t\t\t\t\t
\t\t\t\t\t\t// Checks if one of the terminals is not in the given array
\t\t\t\t\t\tif (!dict.get(source) || !dict.get(target))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.resetEdge(edges[j]);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.resetEdges(this.model.getChildren(cells[i]));
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: resetEdge
 * 
 * Resets the control points of the given edge.
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose points should be reset.
 */
mxGraph.prototype.resetEdge = function(edge)
{
\tvar geo = this.model.getGeometry(edge);
\t
\t// Resets the control points
\tif (geo != null && geo.points != null && geo.points.length > 0)
\t{
\t\tgeo = geo.clone();
\t\tgeo.points = [];
\t\tthis.model.setGeometry(edge, geo);
\t}
\t
\treturn edge;
};

/**
 * Group: Cell connecting and connection constraints
 */

/**
 * Function: getOutlineConstraint
 * 
 * Returns the constraint used to connect to the outline of the given state.
 */
mxGraph.prototype.getOutlineConstraint = function(point, terminalState, me)
{
\tif (terminalState.shape != null)
\t{
\t\tvar bounds = this.view.getPerimeterBounds(terminalState);
\t\tvar direction = terminalState.style[mxConstants.STYLE_DIRECTION];
\t\t
\t\tif (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\tbounds.x += bounds.width / 2 - bounds.height / 2;
\t\t\tbounds.y += bounds.height / 2 - bounds.width / 2;
\t\t\tvar tmp = bounds.width;
\t\t\tbounds.width = bounds.height;
\t\t\tbounds.height = tmp;
\t\t}
\t
\t\tvar alpha = mxUtils.toRadians(terminalState.shape.getShapeRotation());
\t\t
\t\tif (alpha != 0)
\t\t{
\t\t\tvar cos = Math.cos(-alpha);
\t\t\tvar sin = Math.sin(-alpha);
\t
\t\t\tvar ct = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
\t\t\tpoint = mxUtils.getRotatedPoint(point, cos, sin, ct);
\t\t}

\t\tvar sx = 1;
\t\tvar sy = 1;
\t\tvar dx = 0;
\t\tvar dy = 0;
\t\t
\t\t// LATER: Add flipping support for image shapes
\t\tif (this.getModel().isVertex(terminalState.cell))
\t\t{
\t\t\tvar flipH = terminalState.style[mxConstants.STYLE_FLIPH];
\t\t\tvar flipV = terminalState.style[mxConstants.STYLE_FLIPV];
\t\t\t
\t\t\t// Legacy support for stencilFlipH/V
\t\t\tif (terminalState.shape != null && terminalState.shape.stencil != null)
\t\t\t{
\t\t\t\tflipH = mxUtils.getValue(terminalState.style, 'stencilFlipH', 0) == 1 || flipH;
\t\t\t\tflipV = mxUtils.getValue(terminalState.style, 'stencilFlipV', 0) == 1 || flipV;
\t\t\t}
\t\t\t
\t\t\tif (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
\t\t\t{
\t\t\t\tvar tmp = flipH;
\t\t\t\tflipH = flipV;
\t\t\t\tflipV = tmp;
\t\t\t}
\t\t\t
\t\t\tif (flipH)
\t\t\t{
\t\t\t\tsx = -1;
\t\t\t\tdx = -bounds.width;
\t\t\t}
\t\t\t
\t\t\tif (flipV)
\t\t\t{
\t\t\t\tsy = -1;
\t\t\t\tdy = -bounds.height ;
\t\t\t}
\t\t}
\t\t
\t\tpoint = new mxPoint((point.x - bounds.x) * sx - dx + bounds.x, (point.y - bounds.y) * sy - dy + bounds.y);
\t\t
\t\tvar x = (bounds.width == 0) ? 0 : Math.round((point.x - bounds.x) * 1000 / bounds.width) / 1000;
\t\tvar y = (bounds.height == 0) ? 0 : Math.round((point.y - bounds.y) * 1000 / bounds.height) / 1000;
\t\t
\t\treturn new mxConnectionConstraint(new mxPoint(x, y), false);
\t}
\t
\treturn null;
};

/**
 * Function: getAllConnectionConstraints
 * 
 * Returns an array of all <mxConnectionConstraints> for the given terminal. If
 * the shape of the given terminal is a <mxStencilShape> then the constraints
 * of the corresponding <mxStencil> are returned.
 * 
 * Parameters:
 * 
 * terminal - <mxCellState> that represents the terminal.
 * source - Boolean that specifies if the terminal is the source or target.
 */
mxGraph.prototype.getAllConnectionConstraints = function(terminal, source)
{
\tif (terminal != null && terminal.shape != null && terminal.shape.stencil != null)
\t{
\t\treturn terminal.shape.stencil.constraints;
\t}

\treturn null;
};

/**
 * Function: getConnectionConstraint
 * 
 * Returns an <mxConnectionConstraint> that describes the given connection
 * point. This result can then be passed to <getConnectionPoint>.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> that represents the edge.
 * terminal - <mxCellState> that represents the terminal.
 * source - Boolean indicating if the terminal is the source or target.
 */
mxGraph.prototype.getConnectionConstraint = function(edge, terminal, source)
{
\tvar point = null;
\tvar x = edge.style[(source) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];

\tif (x != null)
\t{
\t\tvar y = edge.style[(source) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
\t\t
\t\tif (y != null)
\t\t{
\t\t\tpoint = new mxPoint(parseFloat(x), parseFloat(y));
\t\t}
\t}
\t
\tvar perimeter = false;
\tvar dx = 0, dy = 0;
\t
\tif (point != null)
\t{
\t\tperimeter = mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_EXIT_PERIMETER :
\t\t\tmxConstants.STYLE_ENTRY_PERIMETER, true);

\t\t//Add entry/exit offset
\t\tdx = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DX : mxConstants.STYLE_ENTRY_DX]);
\t\tdy = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DY : mxConstants.STYLE_ENTRY_DY]);
\t\t
\t\tdx = isFinite(dx)? dx : 0;
\t\tdy = isFinite(dy)? dy : 0;
\t}

\treturn new mxConnectionConstraint(point, perimeter, null, dx, dy);
};

/**
 * Function: setConnectionConstraint
 * 
 * Sets the <mxConnectionConstraint> that describes the given connection point.
 * If no constraint is given then nothing is changed. To remove an existing
 * constraint from the given edge, use an empty constraint instead.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge.
 * terminal - <mxCell> that represents the terminal.
 * source - Boolean indicating if the terminal is the source or target.
 * constraint - Optional <mxConnectionConstraint> to be used for this
 * connection.
 */
mxGraph.prototype.setConnectionConstraint = function(edge, terminal, source, constraint)
{
\tif (constraint != null)
\t{
\t\tthis.model.beginUpdate();
\t\t
\t\ttry
\t\t{
\t\t\tif (constraint == null || constraint.point == null)
\t\t\t{
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
\t\t\t\t\tmxConstants.STYLE_ENTRY_X, null, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
\t\t\t\t\tmxConstants.STYLE_ENTRY_Y, null, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
\t\t\t\t\tmxConstants.STYLE_ENTRY_DX, null, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
\t\t\t\t\tmxConstants.STYLE_ENTRY_DY, null, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
\t\t\t\t\tmxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
\t\t\t}
\t\t\telse if (constraint.point != null)
\t\t\t{
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
\t\t\t\t\tmxConstants.STYLE_ENTRY_X, constraint.point.x, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
\t\t\t\t\tmxConstants.STYLE_ENTRY_Y, constraint.point.y, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
\t\t\t\t\tmxConstants.STYLE_ENTRY_DX, constraint.dx, [edge]);
\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
\t\t\t\t\tmxConstants.STYLE_ENTRY_DY, constraint.dy, [edge]);
\t\t\t\t
\t\t\t\t// Only writes 0 since 1 is default
\t\t\t\tif (!constraint.perimeter)
\t\t\t\t{
\t\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
\t\t\t\t\t\tmxConstants.STYLE_ENTRY_PERIMETER, '0', [edge]);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
\t\t\t\t\t\tmxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
\t\t\t\t}
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: getConnectionPoint
 *
 * Returns the nearest point in the list of absolute points or the center
 * of the opposite terminal.
 * 
 * Parameters:
 * 
 * vertex - <mxCellState> that represents the vertex.
 * constraint - <mxConnectionConstraint> that represents the connection point
 * constraint as returned by <getConnectionConstraint>.
 */
mxGraph.prototype.getConnectionPoint = function(vertex, constraint, round)
{
\tround = (round != null) ? round : true;
\tvar point = null;
\t
\tif (vertex != null && constraint.point != null)
\t{
\t\tvar bounds = this.view.getPerimeterBounds(vertex);
        var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
\t\tvar direction = vertex.style[mxConstants.STYLE_DIRECTION];
\t\tvar r1 = 0;
\t\t
\t\t// Bounds need to be rotated by 90 degrees for further computation
\t\tif (direction != null && mxUtils.getValue(vertex.style,
\t\t\tmxConstants.STYLE_ANCHOR_POINT_DIRECTION, 1) == 1)
\t\t{
\t\t\tif (direction == mxConstants.DIRECTION_NORTH)
\t\t\t{
\t\t\t\tr1 += 270;
\t\t\t}
\t\t\telse if (direction == mxConstants.DIRECTION_WEST)
\t\t\t{
\t\t\t\tr1 += 180;
\t\t\t}
\t\t\telse if (direction == mxConstants.DIRECTION_SOUTH)
\t\t\t{
\t\t\t\tr1 += 90;
\t\t\t}

\t\t\t// Bounds need to be rotated by 90 degrees for further computation
\t\t\tif (direction == mxConstants.DIRECTION_NORTH ||
\t\t\t\tdirection == mxConstants.DIRECTION_SOUTH)
\t\t\t{
\t\t\t\tbounds.rotate90();
\t\t\t}
\t\t}

\t\tvar scale = this.view.scale;
\t\tpoint = new mxPoint(bounds.x + constraint.point.x * bounds.width + constraint.dx * scale,
\t\t\t\tbounds.y + constraint.point.y * bounds.height + constraint.dy * scale);
\t\t
\t\t// Rotation for direction before projection on perimeter
\t\tvar r2 = vertex.style[mxConstants.STYLE_ROTATION] || 0;
\t\t
\t\tif (constraint.perimeter)
\t\t{
\t\t\tif (r1 != 0)
\t\t\t{
\t\t\t\t// Only 90 degrees steps possible here so no trig needed
\t\t\t\tvar cos = 0;
\t\t\t\tvar sin = 0;
\t\t\t\t
\t\t\t\tif (r1 == 90)
\t\t\t\t{
\t\t\t\t\tsin = 1;
\t\t\t\t}
\t\t\t\telse if (r1 == 180)
\t\t\t\t{
\t\t\t\t\tcos = -1;
\t\t\t\t}
\t\t\t\telse if (r1 == 270)
\t\t\t\t{
\t\t\t\t\tsin = -1;
\t\t\t\t}
\t\t\t\t
\t\t        point = mxUtils.getRotatedPoint(point, cos, sin, cx);
\t\t\t}
\t
\t\t\tpoint = this.view.getPerimeterPoint(vertex, point, false);
\t\t}
\t\telse
\t\t{
\t\t\tr2 += r1;
\t\t\t
\t\t\tif (this.getModel().isVertex(vertex.cell))
\t\t\t{
\t\t\t\tvar flipH = vertex.style[mxConstants.STYLE_FLIPH] == 1;
\t\t\t\tvar flipV = vertex.style[mxConstants.STYLE_FLIPV] == 1;
\t\t\t\t
\t\t\t\t// Legacy support for stencilFlipH/V
\t\t\t\tif (vertex.shape != null && vertex.shape.stencil != null)
\t\t\t\t{
\t\t\t\t\tflipH = (mxUtils.getValue(vertex.style, 'stencilFlipH', 0) == 1) || flipH;
\t\t\t\t\tflipV = (mxUtils.getValue(vertex.style, 'stencilFlipV', 0) == 1) || flipV;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (direction == mxConstants.DIRECTION_NORTH ||
\t\t\t\t\tdirection == mxConstants.DIRECTION_SOUTH)
\t\t\t\t{
\t\t\t\t\tvar temp = flipH;
\t\t\t\t\tflipH = flipV
\t\t\t\t\tflipV = temp;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (flipH)
\t\t\t\t{
\t\t\t\t\tpoint.x = 2 * bounds.getCenterX() - point.x;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (flipV)
\t\t\t\t{
\t\t\t\t\tpoint.y = 2 * bounds.getCenterY() - point.y;
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Generic rotation after projection on perimeter
\t\tif (r2 != 0 && point != null)
\t\t{
\t        var rad = mxUtils.toRadians(r2);
\t        var cos = Math.cos(rad);
\t        var sin = Math.sin(rad);
\t        
\t        point = mxUtils.getRotatedPoint(point, cos, sin, cx);
\t\t}
\t}
\t
\tif (round && point != null)
\t{
\t\tpoint.x = Math.round(point.x);
\t\tpoint.y = Math.round(point.y);
\t}

\treturn point;
};

/**
 * Function: connectCell
 * 
 * Connects the specified end of the given edge to the given terminal
 * using <cellConnected> and fires <mxEvent.CONNECT_CELL> while the
 * transaction is in progress. Returns the updated edge.
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose terminal should be updated.
 * terminal - <mxCell> that represents the new terminal to be used.
 * source - Boolean indicating if the new terminal is the source or target.
 * constraint - Optional <mxConnectionConstraint> to be used for this
 * connection.
 */
mxGraph.prototype.connectCell = function(edge, terminal, source, constraint)
{
\tthis.model.beginUpdate();
\ttry
\t{
\t\tvar previous = this.model.getTerminal(edge, source);
\t\tthis.cellConnected(edge, terminal, source, constraint);
\t\tthis.fireEvent(new mxEventObject(mxEvent.CONNECT_CELL,
\t\t\t'edge', edge, 'terminal', terminal, 'source', source,
\t\t\t'previous', previous));
\t}
\tfinally
\t{
\t\tthis.model.endUpdate();
\t}

\treturn edge;
};

/**
 * Function: cellConnected
 * 
 * Sets the new terminal for the given edge and resets the edge points if
 * <resetEdgesOnConnect> is true. This method fires
 * <mxEvent.CELL_CONNECTED> while the transaction is in progress.
 * 
 * Parameters:
 * 
 * edge - <mxCell> whose terminal should be updated.
 * terminal - <mxCell> that represents the new terminal to be used.
 * source - Boolean indicating if the new terminal is the source or target.
 * constraint - <mxConnectionConstraint> to be used for this connection.
 */
mxGraph.prototype.cellConnected = function(edge, terminal, source, constraint)
{
\tif (edge != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{
\t\t\tvar previous = this.model.getTerminal(edge, source);

\t\t\t// Updates the constraint
\t\t\tthis.setConnectionConstraint(edge, terminal, source, constraint);
\t\t\t
\t\t\t// Checks if the new terminal is a port, uses the ID of the port in the
\t\t\t// style and the parent of the port as the actual terminal of the edge.
\t\t\tif (this.isPortsEnabled())
\t\t\t{
\t\t\t\tvar id = null;
\t
\t\t\t\tif (this.isPort(terminal))
\t\t\t\t{
\t\t\t\t\tid = terminal.getId();
\t\t\t\t\tterminal = this.getTerminalForPort(terminal, source);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Sets or resets all previous information for connecting to a child port
\t\t\t\tvar key = (source) ? mxConstants.STYLE_SOURCE_PORT :
\t\t\t\t\tmxConstants.STYLE_TARGET_PORT;
\t\t\t\tthis.setCellStyles(key, id, [edge]);
\t\t\t}
\t\t\t
\t\t\tthis.model.setTerminal(edge, terminal, source);
\t\t\t
\t\t\tif (this.resetEdgesOnConnect)
\t\t\t{
\t\t\t\tthis.resetEdge(edge);
\t\t\t}

\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CELL_CONNECTED,
\t\t\t\t'edge', edge, 'terminal', terminal, 'source', source,
\t\t\t\t'previous', previous));
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Function: disconnectGraph
 * 
 * Disconnects the given edges from the terminals which are not in the
 * given array.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be disconnected.
 */
mxGraph.prototype.disconnectGraph = function(cells)
{
\tif (cells != null)
\t{
\t\tthis.model.beginUpdate();
\t\ttry
\t\t{\t\t\t\t\t\t\t
\t\t\tvar scale = this.view.scale;
\t\t\tvar tr = this.view.translate;
\t\t\t
\t\t\t// Fast lookup for finding cells in array
\t\t\tvar dict = new mxDictionary();
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tdict.put(cells[i], true);
\t\t\t}
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (this.model.isEdge(cells[i]))
\t\t\t\t{
\t\t\t\t\tvar geo = this.model.getGeometry(cells[i]);
\t\t\t\t\t
\t\t\t\t\tif (geo != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar state = this.view.getState(cells[i]);
\t\t\t\t\t\tvar pstate = this.view.getState(
\t\t\t\t\t\t\tthis.model.getParent(cells[i]));
\t\t\t\t\t\t
\t\t\t\t\t\tif (state != null &&
\t\t\t\t\t\t\tpstate != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar dx = -pstate.origin.x;
\t\t\t\t\t\t\tvar dy = -pstate.origin.y;
\t\t\t\t\t\t\tvar pts = state.absolutePoints;

\t\t\t\t\t\t\tvar src = this.model.getTerminal(cells[i], true);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (src != null && this.isCellDisconnectable(cells[i], src, true))
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\twhile (src != null && !dict.get(src))
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tsrc = this.model.getParent(src);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (src == null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tgeo.setTerminalPoint(
\t\t\t\t\t\t\t\t\t\tnew mxPoint(pts[0].x / scale - tr.x + dx,
\t\t\t\t\t\t\t\t\t\t\tpts[0].y / scale - tr.y + dy), true);
\t\t\t\t\t\t\t\t\tthis.model.setTerminal(cells[i], null, true);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar trg = this.model.getTerminal(cells[i], false);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (trg != null && this.isCellDisconnectable(cells[i], trg, false))
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\twhile (trg != null && !dict.get(trg))
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttrg = this.model.getParent(trg);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (trg == null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tvar n = pts.length - 1;
\t\t\t\t\t\t\t\t\tgeo.setTerminalPoint(
\t\t\t\t\t\t\t\t\t\tnew mxPoint(pts[n].x / scale - tr.x + dx,
\t\t\t\t\t\t\t\t\t\t\tpts[n].y / scale - tr.y + dy), false);
\t\t\t\t\t\t\t\t\tthis.model.setTerminal(cells[i], null, false);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}

\t\t\t\t\t\t\tthis.model.setGeometry(cells[i], geo);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.model.endUpdate();
\t\t}
\t}
};

/**
 * Group: Drilldown
 */

/**
 * Function: getCurrentRoot
 * 
 * Returns the current root of the displayed cell hierarchy. This is a
 * shortcut to <mxGraphView.currentRoot> in <view>.
 */
mxGraph.prototype.getCurrentRoot = function()
{
\treturn this.view.currentRoot;
};
 
/**
 * Function: getTranslateForRoot
 * 
 * Returns the translation to be used if the given cell is the root cell as
 * an <mxPoint>. This implementation returns null.
 * 
 * Example:
 * 
 * To keep the children at their absolute position while stepping into groups,
 * this function can be overridden as follows.
 * 
 * (code)
 * var offset = new mxPoint(0, 0);
 * 
 * while (cell != null)
 * {
 *   var geo = this.model.getGeometry(cell);
 * 
 *   if (geo != null)
 *   {
 *     offset.x -= geo.x;
 *     offset.y -= geo.y;
 *   }
 * 
 *   cell = this.model.getParent(cell);
 * }
 * 
 * return offset;
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the root.
 */
mxGraph.prototype.getTranslateForRoot = function(cell)
{
\treturn null;
};

/**
 * Function: isPort
 * 
 * Returns true if the given cell is a \"port\", that is, when connecting to
 * it, the cell returned by getTerminalForPort should be used as the
 * terminal and the port should be referenced by the ID in either the
 * mxConstants.STYLE_SOURCE_PORT or the or the
 * mxConstants.STYLE_TARGET_PORT. Note that a port should not be movable.
 * This implementation always returns false.
 * 
 * A typical implementation is the following:
 * 
 * (code)
 * graph.isPort = function(cell)
 * {
 *   var geo = this.getCellGeometry(cell);
 *   
 *   return (geo != null) ? geo.relative : false;
 * };
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the port.
 */
mxGraph.prototype.isPort = function(cell)
{
\treturn false;
};

/**
 * Function: getTerminalForPort
 * 
 * Returns the terminal to be used for a given port. This implementation
 * always returns the parent cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the port.
 * source - If the cell is the source or target port.
 */
mxGraph.prototype.getTerminalForPort = function(cell, source)
{
\treturn this.model.getParent(cell);
};

/**
 * Function: getChildOffsetForCell
 * 
 * Returns the offset to be used for the cells inside the given cell. The
 * root and layer cells may be identified using <mxGraphModel.isRoot> and
 * <mxGraphModel.isLayer>. For all other current roots, the
 * <mxGraphView.currentRoot> field points to the respective cell, so that
 * the following holds: cell == this.view.currentRoot. This implementation
 * returns null.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose offset should be returned.
 */
mxGraph.prototype.getChildOffsetForCell = function(cell)
{
\treturn null;
};

/**
 * Function: enterGroup
 * 
 * Uses the given cell as the root of the displayed cell hierarchy. If no
 * cell is specified then the selection cell is used. The cell is only used
 * if <isValidRoot> returns true.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> to be used as the new root. Default is the
 * selection cell.
 */
mxGraph.prototype.enterGroup = function(cell)
{
\tcell = cell || this.getSelectionCell();
\t
\tif (cell != null && this.isValidRoot(cell))
\t{
\t\tthis.view.setCurrentRoot(cell);
\t\tthis.clearSelection();
\t}
};

/**
 * Function: exitGroup
 * 
 * Changes the current root to the next valid root in the displayed cell
 * hierarchy.
 */
mxGraph.prototype.exitGroup = function()
{
\tvar root = this.model.getRoot();
\tvar current = this.getCurrentRoot();
\t
\tif (current != null)
\t{
\t\tvar next = this.model.getParent(current);
\t\t
\t\t// Finds the next valid root in the hierarchy
\t\twhile (next != root && !this.isValidRoot(next) &&
\t\t\t\tthis.model.getParent(next) != root)
\t\t{
\t\t\tnext = this.model.getParent(next);
\t\t}
\t\t
\t\t// Clears the current root if the new root is
\t\t// the model's root or one of the layers.
\t\tif (next == root || this.model.getParent(next) == root)
\t\t{
\t\t\tthis.view.setCurrentRoot(null);
\t\t}
\t\telse
\t\t{
\t\t\tthis.view.setCurrentRoot(next);
\t\t}
\t\t
\t\tvar state = this.view.getState(current);
\t\t
\t\t// Selects the previous root in the graph
\t\tif (state != null)
\t\t{
\t\t\tthis.setSelectionCell(current);
\t\t}
\t}
};

/**
 * Function: home
 * 
 * Uses the root of the model as the root of the displayed cell hierarchy
 * and selects the previous root.
 */
mxGraph.prototype.home = function()
{
\tvar current = this.getCurrentRoot();
\t
\tif (current != null)
\t{
\t\tthis.view.setCurrentRoot(null);
\t\tvar state = this.view.getState(current);
\t\t
\t\tif (state != null)
\t\t{
\t\t\tthis.setSelectionCell(current);
\t\t}
\t}
};

/**
 * Function: isValidRoot
 * 
 * Returns true if the given cell is a valid root for the cell display
 * hierarchy. This implementation returns true for all non-null values.
 * 
 * Parameters:
 * 
 * cell - <mxCell> which should be checked as a possible root.
 */
mxGraph.prototype.isValidRoot = function(cell)
{
\treturn (cell != null);
};

/**
 * Group: Graph display
 */
 
/**
 * Function: getGraphBounds
 * 
 * Returns the bounds of the visible graph. Shortcut to
 * <mxGraphView.getGraphBounds>. See also: <getBoundingBoxFromGeometry>.
 */
 mxGraph.prototype.getGraphBounds = function()
 {
 \treturn this.view.getGraphBounds();
 };

/**
 * Function: getCellBounds
 * 
 * Returns the scaled, translated bounds for the given cell. See
 * <mxGraphView.getBounds> for arrays.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose bounds should be returned.
 * includeEdge - Optional boolean that specifies if the bounds of
 * the connected edges should be included. Default is false.
 * includeDescendants - Optional boolean that specifies if the bounds
 * of all descendants should be included. Default is false.
 */
mxGraph.prototype.getCellBounds = function(cell, includeEdges, includeDescendants)
{
\tvar cells = [cell];
\t
\t// Includes all connected edges
\tif (includeEdges)
\t{
\t\tcells = cells.concat(this.model.getEdges(cell));
\t}
\t
\tvar result = this.view.getBounds(cells);
\t
\t// Recursively includes the bounds of the children
\tif (includeDescendants)
\t{
\t\tvar childCount = this.model.getChildCount(cell);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar tmp = this.getCellBounds(this.model.getChildAt(cell, i),
\t\t\t\tincludeEdges, true);

\t\t\tif (result != null)
\t\t\t{
\t\t\t\tresult.add(tmp);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tresult = tmp;
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getBoundingBoxFromGeometry
 * 
 * Returns the bounding box for the geometries of the vertices in the
 * given array of cells. This can be used to find the graph bounds during
 * a layout operation (ie. before the last endUpdate) as follows:
 * 
 * (code)
 * var cells = graph.getChildCells(graph.getDefaultParent(), true, true);
 * var bounds = graph.getBoundingBoxFromGeometry(cells, true);
 * (end)
 * 
 * This can then be used to move cells to the origin:
 * 
 * (code)
 * if (bounds.x < 0 || bounds.y < 0)
 * {
 *   graph.moveCells(cells, -Math.min(bounds.x, 0), -Math.min(bounds.y, 0))
 * }
 * (end)
 * 
 * Or to translate the graph view:
 * 
 * (code)
 * if (bounds.x < 0 || bounds.y < 0)
 * {
 *   graph.view.setTranslate(-Math.min(bounds.x, 0), -Math.min(bounds.y, 0));
 * }
 * (end)
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose bounds should be returned.
 * includeEdges - Specifies if edge bounds should be included by computing
 * the bounding box for all points in geometry. Default is false.
 */
mxGraph.prototype.getBoundingBoxFromGeometry = function(cells, includeEdges)
{
\tincludeEdges = (includeEdges != null) ? includeEdges : false;
\tvar result = null;
\t
\tif (cells != null)
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (includeEdges || this.model.isVertex(cells[i]))
\t\t\t{
\t\t\t\t// Computes the bounding box for the points in the geometry
\t\t\t\tvar geo = this.getCellGeometry(cells[i]);
\t\t\t\t
\t\t\t\tif (geo != null)
\t\t\t\t{
\t\t\t\t\tvar bbox = null;
\t\t\t\t\t
\t\t\t\t\tif (this.model.isEdge(cells[i]))
\t\t\t\t\t{
\t\t\t\t\t\tvar addPoint = function(pt)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (pt != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tif (tmp == null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttmp = new mxRectangle(pt.x, pt.y, 0, 0);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttmp.add(new mxRectangle(pt.x, pt.y, 0, 0));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t\t
\t\t\t\t\t\tif (this.model.getTerminal(cells[i], true) == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\taddPoint(geo.getTerminalPoint(true));
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (this.model.getTerminal(cells[i], false) == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\taddPoint(geo.getTerminalPoint(false));
\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\tvar pts = geo.points;
\t\t\t\t\t\t
\t\t\t\t\t\tif (pts != null && pts.length > 0)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar tmp = new mxRectangle(pts[0].x, pts[0].y, 0, 0);

\t\t\t\t\t\t\tfor (var j = 1; j < pts.length; j++)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\taddPoint(pts[j]);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tbbox = tmp;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tvar parent = this.model.getParent(cells[i]);
\t\t\t\t\t\t
\t\t\t\t\t\tif (geo.relative)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (this.model.isVertex(parent) && parent != this.view.currentRoot)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar tmp = this.getBoundingBoxFromGeometry([parent], false);
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (tmp != null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tbbox = new mxRectangle(geo.x * tmp.width, geo.y * tmp.height, geo.width, geo.height);
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (mxUtils.indexOf(cells, parent) >= 0)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tbbox.x += tmp.x;
\t\t\t\t\t\t\t\t\t\tbbox.y += tmp.y;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tbbox = mxRectangle.fromRectangle(geo);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (this.model.isVertex(parent) && mxUtils.indexOf(cells, parent) >= 0)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar tmp = this.getBoundingBoxFromGeometry([parent], false);

\t\t\t\t\t\t\t\tif (tmp != null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tbbox.x += tmp.x;
\t\t\t\t\t\t\t\t\tbbox.y += tmp.y;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (bbox != null && geo.offset != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tbbox.x += geo.offset.x;
\t\t\t\t\t\t\tbbox.y += geo.offset.y;
\t\t\t\t\t\t}

\t\t\t\t\t\tvar style = this.getCurrentCellStyle(cells[i]);
\t\t\t\t\t\t
\t\t\t\t\t\tif (bbox != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar angle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (angle != 0)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tbbox = mxUtils.getBoundingBox(bbox, angle);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (bbox != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (result == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tresult = mxRectangle.fromRectangle(bbox);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tresult.add(bbox);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: refresh
 * 
 * Clears all cell states or the states for the hierarchy starting at the
 * given cell and validates the graph. This fires a refresh event as the
 * last step.
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> for which the cell states should be cleared.
 */
mxGraph.prototype.refresh = function(cell)
{
\tthis.view.clear(cell, cell == null);
\tthis.view.validate();
\tthis.sizeDidChange();
\tthis.fireEvent(new mxEventObject(mxEvent.REFRESH));
};

/**
 * Function: snap
 * 
 * Snaps the given numeric value to the grid if <gridEnabled> is true.
 * 
 * Parameters:
 * 
 * value - Numeric value to be snapped to the grid.
 */
mxGraph.prototype.snap = function(value)
{
\tif (this.gridEnabled)
\t{
\t\tvalue = Math.round(value / this.gridSize ) * this.gridSize;
\t}
\t
\treturn value;
};

/**
 * Function: snapDelta
 * 
 * Snaps the given delta with the given scaled bounds.
 */
mxGraph.prototype.snapDelta = function(delta, bounds, ignoreGrid, ignoreHorizontal, ignoreVertical)
{
\tvar t = this.view.translate;
\tvar s = this.view.scale;
\t
\tif (!ignoreGrid && this.gridEnabled)
\t{
\t\tvar tol = this.gridSize * s * 0.5;
\t\t
\t\tif (!ignoreHorizontal)
\t\t{
\t\t\tvar tx = bounds.x - (this.snap(bounds.x / s - t.x) + t.x) * s;
\t\t\t
\t\t\tif (Math.abs(delta.x- tx) < tol)
\t\t\t{
\t\t\t\tdelta.x = 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdelta.x = this.snap(delta.x / s) * s - tx;
\t\t\t}
\t\t}
\t\t
\t\tif (!ignoreVertical)
\t\t{
\t\t\tvar ty = bounds.y - (this.snap(bounds.y / s - t.y) + t.y) * s;
\t\t\t\t
\t\t\tif (Math.abs(delta.y - ty) < tol)
\t\t\t{
\t\t\t\tdelta.y = 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdelta.y = this.snap(delta.y / s) * s - ty;
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tvar tol = 0.5 * s;
\t\t
\t\tif (!ignoreHorizontal)
\t\t{
\t\t\tvar tx = bounds.x - (Math.round(bounds.x / s - t.x) + t.x) * s;
\t\t\t
\t\t\tif (Math.abs(delta.x - tx) < tol)
\t\t\t{
\t\t\t\tdelta.x = 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdelta.x = Math.round(delta.x / s) * s - tx;
\t\t\t}
\t\t}
\t\t
\t\tif (!ignoreVertical)
\t\t{\t\t
\t\t\tvar ty = bounds.y - (Math.round(bounds.y / s - t.y) + t.y) * s;
\t\t\t
\t\t\tif (Math.abs(delta.y - ty) < tol)
\t\t\t{
\t\t\t\tdelta.y = 0;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdelta.y = Math.round(delta.y / s) * s - ty;
\t\t\t}
\t\t}
\t}
\t
\treturn delta;
};

/**
 * Function: panGraph
 * 
 * Shifts the graph display by the given amount. This is used to preview
 * panning operations, use <mxGraphView.setTranslate> to set a persistent
 * translation of the view. Fires <mxEvent.PAN>.
 * 
 * Parameters:
 * 
 * dx - Amount to shift the graph along the x-axis.
 * dy - Amount to shift the graph along the y-axis.
 */
mxGraph.prototype.panGraph = function(dx, dy)
{
\tif (this.useScrollbarsForPanning && mxUtils.hasScrollbars(this.container))
\t{
\t\tthis.container.scrollLeft = -dx;
\t\tthis.container.scrollTop = -dy;
\t}
\telse
\t{
\t\tvar canvas = this.view.getCanvas();
\t\t
\t\tif (this.dialect == mxConstants.DIALECT_SVG)
\t\t{
\t\t\t// Puts everything inside the container in a DIV so that it
\t\t\t// can be moved without changing the state of the container
\t\t\tif (dx == 0 && dy == 0)
\t\t\t{
\t\t\t\t// Workaround for ignored removeAttribute on SVG element in IE9 standards
\t\t\t\tif (mxClient.IS_IE)
\t\t\t\t{
\t\t\t\t\tcanvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tcanvas.removeAttribute('transform');
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (this.shiftPreview1 != null)
\t\t\t\t{
\t\t\t\t\tvar child = this.shiftPreview1.firstChild;
\t\t\t\t\t
\t\t\t\t\twhile (child != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar next = child.nextSibling;
\t\t\t\t\t\tthis.container.appendChild(child);
\t\t\t\t\t\tchild = next;
\t\t\t\t\t}

\t\t\t\t\tif (this.shiftPreview1.parentNode != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.shiftPreview1.parentNode.removeChild(this.shiftPreview1);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tthis.shiftPreview1 = null;
\t\t\t\t\t
\t\t\t\t\tthis.container.appendChild(canvas.parentNode);
\t\t\t\t\t
\t\t\t\t\tchild = this.shiftPreview2.firstChild;
\t\t\t\t\t
\t\t\t\t\twhile (child != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar next = child.nextSibling;
\t\t\t\t\t\tthis.container.appendChild(child);
\t\t\t\t\t\tchild = next;
\t\t\t\t\t}

\t\t\t\t\tif (this.shiftPreview2.parentNode != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.shiftPreview2.parentNode.removeChild(this.shiftPreview2);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tthis.shiftPreview2 = null;
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tcanvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
\t\t\t\t
\t\t\t\tif (this.shiftPreview1 == null)
\t\t\t\t{
\t\t\t\t\t// Needs two divs for stuff before and after the SVG element
\t\t\t\t\tthis.shiftPreview1 = document.createElement('div');
\t\t\t\t\tthis.shiftPreview1.style.position = 'absolute';
\t\t\t\t\tthis.shiftPreview1.style.overflow = 'visible';
\t\t\t\t\t
\t\t\t\t\tthis.shiftPreview2 = document.createElement('div');
\t\t\t\t\tthis.shiftPreview2.style.position = 'absolute';
\t\t\t\t\tthis.shiftPreview2.style.overflow = 'visible';

\t\t\t\t\tvar current = this.shiftPreview1;
\t\t\t\t\tvar child = this.container.firstChild;
\t\t\t\t\t
\t\t\t\t\twhile (child != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar next = child.nextSibling;
\t\t\t\t\t\t
\t\t\t\t\t\t// SVG element is moved via transform attribute
\t\t\t\t\t\tif (child != canvas.parentNode)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrent.appendChild(child);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrent = this.shiftPreview2;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tchild = next;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Inserts elements only if not empty
\t\t\t\t\tif (this.shiftPreview1.firstChild != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.container.insertBefore(this.shiftPreview1, canvas.parentNode);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (this.shiftPreview2.firstChild != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.container.appendChild(this.shiftPreview2);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.shiftPreview1.style.left = dx + 'px';
\t\t\t\tthis.shiftPreview1.style.top = dy + 'px';
\t\t\t\tthis.shiftPreview2.style.left = dx + 'px';
\t\t\t\tthis.shiftPreview2.style.top = dy + 'px';
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tcanvas.style.left = dx + 'px';
\t\t\tcanvas.style.top = dy + 'px';
\t\t}
\t\t
\t\tthis.panDx = dx;
\t\tthis.panDy = dy;

\t\tthis.fireEvent(new mxEventObject(mxEvent.PAN));
\t}
};

/**
 * Function: zoomIn
 * 
 * Zooms into the graph by <zoomFactor>.
 */
mxGraph.prototype.zoomIn = function()
{
\tthis.zoom(this.zoomFactor);
};

/**
 * Function: zoomOut
 * 
 * Zooms out of the graph by <zoomFactor>.
 */
mxGraph.prototype.zoomOut = function()
{
\tthis.zoom(1 / this.zoomFactor);
};

/**
 * Function: zoomActual
 * 
 * Resets the zoom and panning in the view.
 */
mxGraph.prototype.zoomActual = function()
{
\tif (this.view.scale == 1)
\t{
\t\tthis.view.setTranslate(0, 0);
\t}
\telse
\t{
\t\tthis.view.translate.x = 0;
\t\tthis.view.translate.y = 0;

\t\tthis.view.setScale(1);
\t}
};

/**
 * Function: zoomTo
 * 
 * Zooms the graph to the given scale with an optional boolean center
 * argument, which is passd to <zoom>.
 */
mxGraph.prototype.zoomTo = function(scale, center)
{
\tthis.zoom(scale / this.view.scale, center);
};

/**
 * Function: center
 * 
 * Centers the graph in the container.
 * 
 * Parameters:
 * 
 * horizontal - Optional boolean that specifies if the graph should be centered
 * horizontally. Default is true.
 * vertical - Optional boolean that specifies if the graph should be centered
 * vertically. Default is true.
 * cx - Optional float that specifies the horizontal center. Default is 0.5.
 * cy - Optional float that specifies the vertical center. Default is 0.5.
 */
mxGraph.prototype.center = function(horizontal, vertical, cx, cy)
{
\thorizontal = (horizontal != null) ? horizontal : true;
\tvertical = (vertical != null) ? vertical : true;
\tcx = (cx != null) ? cx : 0.5;
\tcy = (cy != null) ? cy : 0.5;
\t
\tvar hasScrollbars = mxUtils.hasScrollbars(this.container);
\tvar padding = 2 * this.getBorder();
\tvar cw = this.container.clientWidth - padding;
\tvar ch = this.container.clientHeight - padding;
\tvar bounds = this.getGraphBounds();

\tvar t = this.view.translate;
\tvar s = this.view.scale;

\tvar dx = (horizontal) ? cw - bounds.width : 0;
\tvar dy = (vertical) ? ch - bounds.height : 0;
\t
\tif (!hasScrollbars)
\t{
\t\tthis.view.setTranslate((horizontal) ? Math.floor(t.x - bounds.x * s + dx * cx / s) : t.x,
\t\t\t(vertical) ? Math.floor(t.y - bounds.y * s + dy * cy / s) : t.y);
\t}
\telse
\t{
\t\tbounds.x -= t.x;
\t\tbounds.y -= t.y;
\t
\t\tvar sw = this.container.scrollWidth;
\t\tvar sh = this.container.scrollHeight;
\t\t
\t\tif (sw > cw)
\t\t{
\t\t\tdx = 0;
\t\t}
\t\t
\t\tif (sh > ch)
\t\t{
\t\t\tdy = 0;
\t\t}

\t\tthis.view.setTranslate(Math.floor(dx / 2 - bounds.x), Math.floor(dy / 2 - bounds.y));
\t\tthis.container.scrollLeft = (sw - cw) / 2;
\t\tthis.container.scrollTop = (sh - ch) / 2;
\t}
};

/**
 * Function: zoom
 * 
 * Zooms the graph using the given factor. Center is an optional boolean
 * argument that keeps the graph scrolled to the center. If the center argument
 * is omitted, then <centerZoom> will be used as its value.
 */
mxGraph.prototype.zoom = function(factor, center)
{
\tcenter = (center != null) ? center : this.centerZoom;
\tvar scale = Math.round(this.view.scale * factor * 100) / 100;
\tvar state = this.view.getState(this.getSelectionCell());
\tfactor = scale / this.view.scale;
\t
\tif (this.keepSelectionVisibleOnZoom && state != null)
\t{
\t\tvar rect = new mxRectangle(state.x * factor, state.y * factor,
\t\t\tstate.width * factor, state.height * factor);
\t\t
\t\t// Refreshes the display only once if a scroll is carried out
\t\tthis.view.scale = scale;
\t\t
\t\tif (!this.scrollRectToVisible(rect))
\t\t{
\t\t\tthis.view.revalidate();
\t\t\t
\t\t\t// Forces an event to be fired but does not revalidate again
\t\t\tthis.view.setScale(scale);
\t\t}
\t}
\telse
\t{
\t\tvar hasScrollbars = mxUtils.hasScrollbars(this.container);
\t\t
\t\tif (center && !hasScrollbars)
\t\t{
\t\t\tvar dx = this.container.offsetWidth;
\t\t\tvar dy = this.container.offsetHeight;
\t\t\t
\t\t\tif (factor > 1)
\t\t\t{
\t\t\t\tvar f = (factor - 1) / (scale * 2);
\t\t\t\tdx *= -f;
\t\t\t\tdy *= -f;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar f = (1 / factor - 1) / (this.view.scale * 2);
\t\t\t\tdx *= f;
\t\t\t\tdy *= f;
\t\t\t}

\t\t\tthis.view.scaleAndTranslate(scale,
\t\t\t\tthis.view.translate.x + dx,
\t\t\t\tthis.view.translate.y + dy);
\t\t}
\t\telse
\t\t{
\t\t\t// Allows for changes of translate and scrollbars during setscale
\t\t\tvar tx = this.view.translate.x;
\t\t\tvar ty = this.view.translate.y;
\t\t\tvar sl = this.container.scrollLeft;
\t\t\tvar st = this.container.scrollTop;
\t\t\t
\t\t\tthis.view.setScale(scale);
\t\t\t
\t\t\tif (hasScrollbars)
\t\t\t{
\t\t\t\tvar dx = 0;
\t\t\t\tvar dy = 0;
\t\t\t\t
\t\t\t\tif (center)
\t\t\t\t{
\t\t\t\t\tdx = this.container.offsetWidth * (factor - 1) / 2;
\t\t\t\t\tdy = this.container.offsetHeight * (factor - 1) / 2;
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.container.scrollLeft = (this.view.translate.x - tx) * this.view.scale + Math.round(sl * factor + dx);
\t\t\t\tthis.container.scrollTop = (this.view.translate.y - ty) * this.view.scale + Math.round(st * factor + dy);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: zoomToRect
 * 
 * Zooms the graph to the specified rectangle. If the rectangle does not have same aspect
 * ratio as the display container, it is increased in the smaller relative dimension only
 * until the aspect match. The original rectangle is centralised within this expanded one.
 * 
 * Note that the input rectangular must be un-scaled and un-translated.
 * 
 * Parameters:
 * 
 * rect - The un-scaled and un-translated rectangluar region that should be just visible 
 * after the operation
 */
mxGraph.prototype.zoomToRect = function(rect)
{
\tvar scaleX = this.container.clientWidth / rect.width;
\tvar scaleY = this.container.clientHeight / rect.height;
\tvar aspectFactor = scaleX / scaleY;

\t// Remove any overlap of the rect outside the client area
\trect.x = Math.max(0, rect.x);
\trect.y = Math.max(0, rect.y);
\tvar rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
\tvar rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
\trect.width = rectRight - rect.x;
\trect.height = rectBottom - rect.y;

\t// The selection area has to be increased to the same aspect
\t// ratio as the container, centred around the centre point of the 
\t// original rect passed in.
\tif (aspectFactor < 1.0)
\t{
\t\t// Height needs increasing
\t\tvar newHeight = rect.height / aspectFactor;
\t\tvar deltaHeightBuffer = (newHeight - rect.height) / 2.0;
\t\trect.height = newHeight;
\t\t
\t\t// Assign up to half the buffer to the upper part of the rect, not crossing 0
\t\t// put the rest on the bottom
\t\tvar upperBuffer = Math.min(rect.y , deltaHeightBuffer);
\t\trect.y = rect.y - upperBuffer;
\t\t
\t\t// Check if the bottom has extended too far
\t\trectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
\t\trect.height = rectBottom - rect.y;
\t}
\telse
\t{
\t\t// Width needs increasing
\t\tvar newWidth = rect.width * aspectFactor;
\t\tvar deltaWidthBuffer = (newWidth - rect.width) / 2.0;
\t\trect.width = newWidth;
\t\t
\t\t// Assign up to half the buffer to the upper part of the rect, not crossing 0
\t\t// put the rest on the bottom
\t\tvar leftBuffer = Math.min(rect.x , deltaWidthBuffer);
\t\trect.x = rect.x - leftBuffer;
\t\t
\t\t// Check if the right hand side has extended too far
\t\trectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
\t\trect.width = rectRight - rect.x;
\t}

\tvar scale = this.container.clientWidth / rect.width;
\tvar newScale = this.view.scale * scale;

\tif (!mxUtils.hasScrollbars(this.container))
\t{
\t\tthis.view.scaleAndTranslate(newScale, (this.view.translate.x - rect.x / this.view.scale), (this.view.translate.y - rect.y / this.view.scale));
\t}
\telse
\t{
\t\tthis.view.setScale(newScale);
\t\tthis.container.scrollLeft = Math.round(rect.x * scale);
\t\tthis.container.scrollTop = Math.round(rect.y * scale);
\t}
};

/**
 * Function: scrollCellToVisible
 * 
 * Pans the graph so that it shows the given cell. Optionally the cell may
 * be centered in the container.
 * 
 * To center a given graph if the <container> has no scrollbars, use the following code.
 * 
 * [code]
 * var bounds = graph.getGraphBounds();
 * graph.view.setTranslate(-bounds.x - (bounds.width - container.clientWidth) / 2,
 * \t\t\t\t\t\t   -bounds.y - (bounds.height - container.clientHeight) / 2);
 * [/code]
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be made visible.
 * center - Optional boolean flag. Default is false.
 */
mxGraph.prototype.scrollCellToVisible = function(cell, center)
{
\tvar x = -this.view.translate.x;
\tvar y = -this.view.translate.y;

\tvar state = this.view.getState(cell);

\tif (state != null)
\t{
\t\tvar bounds = new mxRectangle(x + state.x, y + state.y, state.width,
\t\t\tstate.height);

\t\tif (center && this.container != null)
\t\t{
\t\t\tvar w = this.container.clientWidth;
\t\t\tvar h = this.container.clientHeight;

\t\t\tbounds.x = bounds.getCenterX() - w / 2;
\t\t\tbounds.width = w;
\t\t\tbounds.y = bounds.getCenterY() - h / 2;
\t\t\tbounds.height = h;
\t\t}
\t\t
\t\tvar tr = new mxPoint(this.view.translate.x, this.view.translate.y);

\t\tif (this.scrollRectToVisible(bounds))
\t\t{
\t\t\t// Triggers an update via the view's event source
\t\t\tvar tr2 = new mxPoint(this.view.translate.x, this.view.translate.y);
\t\t\tthis.view.translate.x = tr.x;
\t\t\tthis.view.translate.y = tr.y;
\t\t\tthis.view.setTranslate(tr2.x, tr2.y);
\t\t}
\t}
};

/**
 * Function: scrollRectToVisible
 * 
 * Pans the graph so that it shows the given rectangle.
 * 
 * Parameters:
 * 
 * rect - <mxRectangle> to be made visible.
 */
mxGraph.prototype.scrollRectToVisible = function(rect)
{
\tvar isChanged = false;
\t
\tif (rect != null)
\t{
\t\tvar w = this.container.offsetWidth;
\t\tvar h = this.container.offsetHeight;

        var widthLimit = Math.min(w, rect.width);
        var heightLimit = Math.min(h, rect.height);

\t\tif (mxUtils.hasScrollbars(this.container))
\t\t{
\t\t\tvar c = this.container;
\t\t\trect.x += this.view.translate.x;
\t\t\trect.y += this.view.translate.y;
\t\t\tvar dx = c.scrollLeft - rect.x;
\t\t\tvar ddx = Math.max(dx - c.scrollLeft, 0);

\t\t\tif (dx > 0)
\t\t\t{
\t\t\t\tc.scrollLeft -= dx + 2;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdx = rect.x + widthLimit - c.scrollLeft - c.clientWidth;

\t\t\t\tif (dx > 0)
\t\t\t\t{
\t\t\t\t\tc.scrollLeft += dx + 2;
\t\t\t\t}
\t\t\t}

\t\t\tvar dy = c.scrollTop - rect.y;
\t\t\tvar ddy = Math.max(0, dy - c.scrollTop);

\t\t\tif (dy > 0)
\t\t\t{
\t\t\t\tc.scrollTop -= dy + 2;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdy = rect.y + heightLimit - c.scrollTop - c.clientHeight;

\t\t\t\tif (dy > 0)
\t\t\t\t{
\t\t\t\t\tc.scrollTop += dy + 2;
\t\t\t\t}
\t\t\t}

\t\t\tif (!this.useScrollbarsForPanning && (ddx != 0 || ddy != 0))
\t\t\t{
\t\t\t\tthis.view.setTranslate(ddx, ddy);
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar x = -this.view.translate.x;
\t\t\tvar y = -this.view.translate.y;

\t\t\tvar s = this.view.scale;

\t\t\tif (rect.x + widthLimit > x + w)
\t\t\t{
\t\t\t\tthis.view.translate.x -= (rect.x + widthLimit - w - x) / s;
\t\t\t\tisChanged = true;
\t\t\t}

\t\t\tif (rect.y + heightLimit > y + h)
\t\t\t{
\t\t\t\tthis.view.translate.y -= (rect.y + heightLimit - h - y) / s;
\t\t\t\tisChanged = true;
\t\t\t}

\t\t\tif (rect.x < x)
\t\t\t{
\t\t\t\tthis.view.translate.x += (x - rect.x) / s;
\t\t\t\tisChanged = true;
\t\t\t}

\t\t\tif (rect.y  < y)
\t\t\t{
\t\t\t\tthis.view.translate.y += (y - rect.y) / s;
\t\t\t\tisChanged = true;
\t\t\t}

\t\t\tif (isChanged)
\t\t\t{
\t\t\t\tthis.view.refresh();
\t\t\t\t
\t\t\t\t// Repaints selection marker (ticket 18)
\t\t\t\tif (this.selectionCellsHandler != null)
\t\t\t\t{
\t\t\t\t\tthis.selectionCellsHandler.refresh();
\t\t\t\t}
\t\t\t}
\t\t}
\t}

\treturn isChanged;
};

/**
 * Function: getCellGeometry
 * 
 * Returns the <mxGeometry> for the given cell. This implementation uses
 * <mxGraphModel.getGeometry>. Subclasses can override this to implement
 * specific geometries for cells in only one graph, that is, it can return
 * geometries that depend on the current state of the view.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose geometry should be returned.
 */
mxGraph.prototype.getCellGeometry = function(cell)
{
\treturn this.model.getGeometry(cell);
};

/**
 * Function: isCellVisible
 * 
 * Returns true if the given cell is visible in this graph. This
 * implementation uses <mxGraphModel.isVisible>. Subclassers can override
 * this to implement specific visibility for cells in only one graph, that
 * is, without affecting the visible state of the cell.
 * 
 * When using dynamic filter expressions for cell visibility, then the
 * graph should be revalidated after the filter expression has changed.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose visible state should be returned.
 */
mxGraph.prototype.isCellVisible = function(cell)
{
\treturn this.model.isVisible(cell);
};

/**
 * Function: isCellCollapsed
 * 
 * Returns true if the given cell is collapsed in this graph. This
 * implementation uses <mxGraphModel.isCollapsed>. Subclassers can override
 * this to implement specific collapsed states for cells in only one graph,
 * that is, without affecting the collapsed state of the cell.
 * 
 * When using dynamic filter expressions for the collapsed state, then the
 * graph should be revalidated after the filter expression has changed.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose collapsed state should be returned.
 */
mxGraph.prototype.isCellCollapsed = function(cell)
{
\treturn this.model.isCollapsed(cell);
};

/**
 * Function: isCellConnectable
 * 
 * Returns true if the given cell is connectable in this graph. This
 * implementation uses <mxGraphModel.isConnectable>. Subclassers can override
 * this to implement specific connectable states for cells in only one graph,
 * that is, without affecting the connectable state of the cell in the model.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose connectable state should be returned.
 */
mxGraph.prototype.isCellConnectable = function(cell)
{
\treturn this.model.isConnectable(cell);
};

/**
 * Function: isOrthogonal
 * 
 * Returns true if perimeter points should be computed such that the
 * resulting edge has only horizontal or vertical segments.
 * 
 * Parameters:
 * 
 * edge - <mxCellState> that represents the edge.
 */
mxGraph.prototype.isOrthogonal = function(edge)
{
\tvar orthogonal = edge.style[mxConstants.STYLE_ORTHOGONAL];
\t
\tif (orthogonal != null)
\t{
\t\treturn orthogonal;
\t}
\t
\tvar tmp = this.view.getEdgeStyle(edge);
\t
\treturn tmp == mxEdgeStyle.SegmentConnector ||
\t\ttmp == mxEdgeStyle.ElbowConnector ||
\t\ttmp == mxEdgeStyle.SideToSide ||
\t\ttmp == mxEdgeStyle.TopToBottom ||
\t\ttmp == mxEdgeStyle.EntityRelation ||
\t\ttmp == mxEdgeStyle.OrthConnector;
};

/**
 * Function: isLoop
 * 
 * Returns true if the given cell state is a loop.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents a potential loop.
 */
mxGraph.prototype.isLoop = function(state)
{
\tvar src = state.getVisibleTerminalState(true);
\tvar trg = state.getVisibleTerminalState(false);
\t
\treturn (src != null && src == trg);
};

/**
 * Function: isCloneEvent
 * 
 * Returns true if the given event is a clone event. This implementation
 * returns true if control is pressed.
 */
mxGraph.prototype.isCloneEvent = function(evt)
{
\treturn mxEvent.isControlDown(evt);
};

/**
 * Function: isTransparentClickEvent
 * 
 * Hook for implementing click-through behaviour on selected cells. If this
 * returns true the cell behind the selected cell will be selected. This
 * implementation returns false;
 */
mxGraph.prototype.isTransparentClickEvent = function(evt)
{
\treturn false;
};

/**
 * Function: isToggleEvent
 * 
 * Returns true if the given event is a toggle event. This implementation
 * returns true if the meta key (Cmd) is pressed on Macs or if control is
 * pressed on any other platform.
 */
mxGraph.prototype.isToggleEvent = function(evt)
{
\treturn (mxClient.IS_MAC) ? mxEvent.isMetaDown(evt) : mxEvent.isControlDown(evt);
};

/**
 * Function: isGridEnabledEvent
 * 
 * Returns true if the given mouse event should be aligned to the grid.
 */
mxGraph.prototype.isGridEnabledEvent = function(evt)
{
\treturn evt != null && !mxEvent.isAltDown(evt);
};

/**
 * Function: isConstrainedEvent
 * 
 * Returns true if the given mouse event should be aligned to the grid.
 */
mxGraph.prototype.isConstrainedEvent = function(evt)
{
\treturn mxEvent.isShiftDown(evt);
};

/**
 * Function: isIgnoreTerminalEvent
 * 
 * Returns true if the given mouse event should not allow any connections to be
 * made. This implementation returns false.
 */
mxGraph.prototype.isIgnoreTerminalEvent = function(evt)
{
\treturn false;
};

/**
 * Group: Validation
 */

/**
 * Function: validationAlert
 * 
 * Displays the given validation error in a dialog. This implementation uses
 * mxUtils.alert.
 */
mxGraph.prototype.validationAlert = function(message)
{
\tmxUtils.alert(message);
};

/**
 * Function: isEdgeValid
 * 
 * Checks if the return value of <getEdgeValidationError> for the given
 * arguments is null.
 *  
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to validate.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 */
mxGraph.prototype.isEdgeValid = function(edge, source, target)
{
\treturn this.getEdgeValidationError(edge, source, target) == null;
};

/**
 * Function: getEdgeValidationError
 * 
 * Returns the validation error message to be displayed when inserting or
 * changing an edges' connectivity. A return value of null means the edge
 * is valid, a return value of '' means it's not valid, but do not display
 * an error message. Any other (non-empty) string returned from this method
 * is displayed as an error message when trying to connect an edge to a
 * source and target. This implementation uses the <multiplicities>, and
 * checks <multigraph>, <allowDanglingEdges> and <allowLoops> to generate
 * validation errors.
 * 
 * For extending this method with specific checks for source/target cells,
 * the method can be extended as follows. Returning an empty string means
 * the edge is invalid with no error message, a non-null string specifies
 * the error message, and null means the edge is valid.
 * 
 * (code)
 * graph.getEdgeValidationError = function(edge, source, target)
 * {
 *   if (source != null && target != null &&
 *     this.model.getValue(source) != null &&
 *     this.model.getValue(target) != null)
 *   {
 *     if (target is not valid for source)
 *     {
 *       return 'Invalid Target';
 *     }
 *   }
 *   
 *   // \"Supercall\"
 *   return mxGraph.prototype.getEdgeValidationError.apply(this, arguments);
 * }
 * (end)
 *  
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to validate.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 */
mxGraph.prototype.getEdgeValidationError = function(edge, source, target)
{
\tif (edge != null && !this.isAllowDanglingEdges() && (source == null || target == null))
\t{
\t\treturn '';
\t}
\t
\tif (edge != null && this.model.getTerminal(edge, true) == null &&
\t\tthis.model.getTerminal(edge, false) == null)\t
\t{
\t\treturn null;
\t}
\t
\t// Checks if we're dealing with a loop
\tif (!this.allowLoops && source == target && source != null)
\t{
\t\treturn '';
\t}
\t
\t// Checks if the connection is generally allowed
\tif (!this.isValidConnection(source, target))
\t{
\t\treturn '';
\t}

\tif (source != null && target != null)
\t{
\t\tvar error = '';

\t\t// Checks if the cells are already connected
\t\t// and adds an error message if required\t\t\t
\t\tif (!this.multigraph)
\t\t{
\t\t\tvar tmp = this.model.getEdgesBetween(source, target, true);
\t\t\t
\t\t\t// Checks if the source and target are not connected by another edge
\t\t\tif (tmp.length > 1 || (tmp.length == 1 && tmp[0] != edge))
\t\t\t{
\t\t\t\terror += (mxResources.get(this.alreadyConnectedResource) ||
\t\t\t\t\tthis.alreadyConnectedResource)+'\\n';
\t\t\t}
\t\t}

\t\t// Gets the number of outgoing edges from the source
\t\t// and the number of incoming edges from the target
\t\t// without counting the edge being currently changed.
\t\tvar sourceOut = this.model.getDirectedEdgeCount(source, true, edge);
\t\tvar targetIn = this.model.getDirectedEdgeCount(target, false, edge);

\t\t// Checks the change against each multiplicity rule
\t\tif (this.multiplicities != null)
\t\t{
\t\t\tfor (var i = 0; i < this.multiplicities.length; i++)
\t\t\t{
\t\t\t\tvar err = this.multiplicities[i].check(this, edge, source,
\t\t\t\t\ttarget, sourceOut, targetIn);
\t\t\t\t
\t\t\t\tif (err != null)
\t\t\t\t{
\t\t\t\t\terror += err;
\t\t\t\t}
\t\t\t}
\t\t}

\t\t// Validates the source and target terminals independently
\t\tvar err = this.validateEdge(edge, source, target);
\t\t
\t\tif (err != null)
\t\t{
\t\t\terror += err;
\t\t}
\t\t
\t\treturn (error.length > 0) ? error : null;
\t}
\t
\treturn (this.allowDanglingEdges) ? null : '';
};

/**
 * Function: validateEdge
 * 
 * Hook method for subclassers to return an error message for the given
 * edge and terminals. This implementation returns null.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to validate.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 */
mxGraph.prototype.validateEdge = function(edge, source, target)
{
\treturn null;
};

/**
 * Function: validateGraph
 * 
 * Validates the graph by validating each descendant of the given cell or
 * the root of the model. Context is an object that contains the validation
 * state for the complete validation run. The validation errors are
 * attached to their cells using <setCellWarning>. Returns null in the case of
 * successful validation or an array of strings (warnings) in the case of
 * failed validations.
 * 
 * Paramters:
 * 
 * cell - Optional <mxCell> to start the validation recursion. Default is
 * the graph root.
 * context - Object that represents the global validation state.
 */
mxGraph.prototype.validateGraph = function(cell, context)
{
\tcell = (cell != null) ? cell : this.model.getRoot();
\tcontext = (context != null) ? context : new Object();
\t
\tvar isValid = true;
\tvar childCount = this.model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar tmp = this.model.getChildAt(cell, i);
\t\tvar ctx = context;
\t\t
\t\tif (this.isValidRoot(tmp))
\t\t{
\t\t\tctx = new Object();
\t\t}
\t\t
\t\tvar warn = this.validateGraph(tmp, ctx);
\t\t
\t\tif (warn != null)
\t\t{
\t\t\tthis.setCellWarning(tmp, warn.replace(/\\n/g, '<br>'));
\t\t}
\t\telse
\t\t{
\t\t\tthis.setCellWarning(tmp, null);
\t\t}
\t\t
\t\tisValid = isValid && warn == null;
\t}
\t
\tvar warning = '';
\t
\t// Adds error for invalid children if collapsed (children invisible)
\tif (this.isCellCollapsed(cell) && !isValid)
\t{
\t\twarning += (mxResources.get(this.containsValidationErrorsResource) ||
\t\t\tthis.containsValidationErrorsResource) + '\\n';
\t}
\t
\t// Checks edges and cells using the defined multiplicities
\tif (this.model.isEdge(cell))
\t{
\t\twarning += this.getEdgeValidationError(cell,
\t\tthis.model.getTerminal(cell, true),
\t\tthis.model.getTerminal(cell, false)) || '';
\t}
\telse
\t{
\t\twarning += this.getCellValidationError(cell) || '';
\t}
\t
\t// Checks custom validation rules
\tvar err = this.validateCell(cell, context);
\t
\tif (err != null)
\t{
\t\twarning += err;
\t}
\t
\t// Updates the display with the warning icons
\t// before any potential alerts are displayed.
\t// LATER: Move this into addCellOverlay. Redraw
\t// should check if overlay was added or removed.
\tif (this.model.getParent(cell) == null)
\t{
\t\tthis.view.validate();
\t}

\treturn (warning.length > 0 || !isValid) ? warning : null;
};

/**
 * Function: getCellValidationError
 * 
 * Checks all <multiplicities> that cannot be enforced while the graph is
 * being modified, namely, all multiplicities that require a minimum of
 * 1 edge.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the multiplicities should be checked.
 */
mxGraph.prototype.getCellValidationError = function(cell)
{
\tvar outCount = this.model.getDirectedEdgeCount(cell, true);
\tvar inCount = this.model.getDirectedEdgeCount(cell, false);
\tvar value = this.model.getValue(cell);
\tvar error = '';

\tif (this.multiplicities != null)
\t{
\t\tfor (var i = 0; i < this.multiplicities.length; i++)
\t\t{
\t\t\tvar rule = this.multiplicities[i];
\t\t\t
\t\t\tif (rule.source && mxUtils.isNode(value, rule.type,
\t\t\t\trule.attr, rule.value) && (outCount > rule.max ||
\t\t\t\toutCount < rule.min))
\t\t\t{
\t\t\t\terror += rule.countError + '\\n';
\t\t\t}
\t\t\telse if (!rule.source && mxUtils.isNode(value, rule.type,
\t\t\t\t\trule.attr, rule.value) && (inCount > rule.max ||
\t\t\t\t\tinCount < rule.min))
\t\t\t{
\t\t\t\terror += rule.countError + '\\n';
\t\t\t}
\t\t}
\t}

\treturn (error.length > 0) ? error : null;
};

/**
 * Function: validateCell
 * 
 * Hook method for subclassers to return an error message for the given
 * cell and validation context. This implementation returns null. Any HTML
 * breaks will be converted to linefeeds in the calling method.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the cell to validate.
 * context - Object that represents the global validation state.
 */
mxGraph.prototype.validateCell = function(cell, context)
{
\treturn null;
};

/**
 * Group: Graph appearance
 */

/**
 * Function: getBackgroundImage
 * 
 * Returns the <backgroundImage> as an <mxImage>.
 */
mxGraph.prototype.getBackgroundImage = function()
{
\treturn this.backgroundImage;
};

/**
 * Function: setBackgroundImage
 * 
 * Sets the new <backgroundImage>.
 * 
 * Parameters:
 * 
 * image - New <mxImage> to be used for the background.
 */
mxGraph.prototype.setBackgroundImage = function(image)
{
\tthis.backgroundImage = image;
};

/**
 * Function: getFoldingImage
 * 
 * Returns the <mxImage> used to display the collapsed state of
 * the specified cell state. This returns null for all edges.
 */
mxGraph.prototype.getFoldingImage = function(state)
{
\tif (state != null && this.foldingEnabled && !this.getModel().isEdge(state.cell))
\t{
\t\tvar tmp = this.isCellCollapsed(state.cell);
\t\t
\t\tif (this.isCellFoldable(state.cell, !tmp))
\t\t{
\t\t\treturn (tmp) ? this.collapsedImage : this.expandedImage;
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: convertValueToString
 * 
 * Returns the textual representation for the given cell. This
 * implementation returns the nodename or string-representation of the user
 * object.
 *
 * Example:
 * 
 * The following returns the label attribute from the cells user
 * object if it is an XML node.
 * 
 * (code)
 * graph.convertValueToString = function(cell)
 * {
 * \treturn cell.getAttribute('label');
 * }
 * (end)
 * 
 * See also: <cellLabelChanged>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose textual representation should be returned.
 */
mxGraph.prototype.convertValueToString = function(cell)
{
\tvar value = this.model.getValue(cell);
\t
\tif (value != null)
\t{
\t\tif (mxUtils.isNode(value))
\t\t{
\t\t\treturn value.nodeName;
\t\t}
\t\telse if (typeof(value.toString) == 'function')
\t\t{
\t\t\treturn value.toString();
\t\t}
\t}
\t
\treturn '';
};

/**
 * Function: getLabel
 * 
 * Returns a string or DOM node that represents the label for the given
 * cell. This implementation uses <convertValueToString> if <labelsVisible>
 * is true. Otherwise it returns an empty string.
 * 
 * To truncate a label to match the size of the cell, the following code
 * can be used.
 * 
 * (code)
 * graph.getLabel = function(cell)
 * {
 *   var label = mxGraph.prototype.getLabel.apply(this, arguments);
 * 
 *   if (label != null && this.model.isVertex(cell))
 *   {
 *     var geo = this.getCellGeometry(cell);
 * 
 *     if (geo != null)
 *     {
 *       var max = parseInt(geo.width / 8);
 * 
 *       if (label.length > max)
 *       {
 *         label = label.substring(0, max)+'...';
 *       }
 *     }
 *   } 
 *   return mxUtils.htmlEntities(label);
 * }
 * (end)
 * 
 * A resize listener is needed in the graph to force a repaint of the label
 * after a resize.
 * 
 * (code)
 * graph.addListener(mxEvent.RESIZE_CELLS, function(sender, evt)
 * {
 *   var cells = evt.getProperty('cells');
 * 
 *   for (var i = 0; i < cells.length; i++)
 *   {
 *     this.view.removeState(cells[i]);
 *   }
 * });
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose label should be returned.
 */
mxGraph.prototype.getLabel = function(cell)
{
\tvar result = '';
\t
\tif (this.labelsVisible && cell != null)
\t{
\t\tvar style = this.getCurrentCellStyle(cell);
\t\t
\t\tif (!mxUtils.getValue(style, mxConstants.STYLE_NOLABEL, false))
\t\t{
\t\t\tresult = this.convertValueToString(cell);
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: isHtmlLabel
 * 
 * Returns true if the label must be rendered as HTML markup. The default
 * implementation returns <htmlLabels>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose label should be displayed as HTML markup.
 */
mxGraph.prototype.isHtmlLabel = function(cell)
{
\treturn this.isHtmlLabels();
};
 
/**
 * Function: isHtmlLabels
 * 
 * Returns <htmlLabels>.
 */
mxGraph.prototype.isHtmlLabels = function()
{
\treturn this.htmlLabels;
};
 
/**
 * Function: setHtmlLabels
 * 
 * Sets <htmlLabels>.
 */
mxGraph.prototype.setHtmlLabels = function(value)
{
\tthis.htmlLabels = value;
};

/**
 * Function: isWrapping
 * 
 * This enables wrapping for HTML labels.
 * 
 * Returns true if no white-space CSS style directive should be used for
 * displaying the given cells label. This implementation returns true if
 * <mxConstants.STYLE_WHITE_SPACE> in the style of the given cell is 'wrap'.
 * 
 * This is used as a workaround for IE ignoring the white-space directive
 * of child elements if the directive appears in a parent element. It
 * should be overridden to return true if a white-space directive is used
 * in the HTML markup that represents the given cells label. In order for
 * HTML markup to work in labels, <isHtmlLabel> must also return true
 * for the given cell.
 * 
 * Example:
 * 
 * (code)
 * graph.getLabel = function(cell)
 * {
 *   var tmp = mxGraph.prototype.getLabel.apply(this, arguments); // \"supercall\"
 *   
 *   if (this.model.isEdge(cell))
 *   {
 *     tmp = '<div style=\"width: 150px; white-space:normal;\">'+tmp+'</div>';
 *   }
 *   
 *   return tmp;
 * }
 * 
 * graph.isWrapping = function(state)
 * {
 * \t return this.model.isEdge(state.cell);
 * }
 * (end)
 * 
 * Makes sure no edge label is wider than 150 pixels, otherwise the content
 * is wrapped. Note: No width must be specified for wrapped vertex labels as
 * the vertex defines the width in its geometry.
 * 
 * Parameters:
 * 
 * state - <mxCell> whose label should be wrapped.
 */
mxGraph.prototype.isWrapping = function(cell)
{
\treturn this.getCurrentCellStyle(cell)[mxConstants.STYLE_WHITE_SPACE] == 'wrap';
};

/**
 * Function: isLabelClipped
 * 
 * Returns true if the overflow portion of labels should be hidden. If this
 * returns true then vertex labels will be clipped to the size of the vertices.
 * This implementation returns true if <mxConstants.STYLE_OVERFLOW> in the
 * style of the given cell is 'hidden'.
 * 
 * Parameters:
 * 
 * state - <mxCell> whose label should be clipped.
 */
mxGraph.prototype.isLabelClipped = function(cell)
{
\treturn this.getCurrentCellStyle(cell)[mxConstants.STYLE_OVERFLOW] == 'hidden';
};

/**
 * Function: getTooltip
 * 
 * Returns the string or DOM node that represents the tooltip for the given
 * state, node and coordinate pair. This implementation checks if the given
 * node is a folding icon or overlay and returns the respective tooltip. If
 * this does not result in a tooltip, the handler for the cell is retrieved
 * from <selectionCellsHandler> and the optional getTooltipForNode method is
 * called. If no special tooltip exists here then <getTooltipForCell> is used
 * with the cell in the given state as the argument to return a tooltip for the
 * given state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose tooltip should be returned.
 * node - DOM node that is currently under the mouse.
 * x - X-coordinate of the mouse.
 * y - Y-coordinate of the mouse.
 */
mxGraph.prototype.getTooltip = function(state, node, x, y)
{
\tvar tip = null;
\t
\tif (state != null)
\t{
\t\t// Checks if the mouse is over the folding icon
\t\tif (state.control != null && (node == state.control.node ||
\t\t\tnode.parentNode == state.control.node))
\t\t{
\t\t\ttip = this.collapseExpandResource;
\t\t\ttip = mxUtils.htmlEntities(mxResources.get(tip) || tip).replace(/\\\\n/g, '<br>');
\t\t}

\t\tif (tip == null && state.overlays != null)
\t\t{
\t\t\tstate.overlays.visit(function(id, shape)
\t\t\t{
\t\t\t\t// LATER: Exit loop if tip is not null
\t\t\t\tif (tip == null && (node == shape.node || node.parentNode == shape.node))
\t\t\t\t{
\t\t\t\t\ttip = shape.overlay.toString();
\t\t\t\t}
\t\t\t});
\t\t}
\t\t
\t\tif (tip == null)
\t\t{
\t\t\tvar handler = this.selectionCellsHandler.getHandler(state.cell);
\t\t\t
\t\t\tif (handler != null && typeof(handler.getTooltipForNode) == 'function')
\t\t\t{
\t\t\t\ttip = handler.getTooltipForNode(node);
\t\t\t}
\t\t}
\t\t
\t\tif (tip == null)
\t\t{
\t\t\ttip = this.getTooltipForCell(state.cell);
\t\t}
\t}
\t
\treturn tip;
};

/**
 * Function: getTooltipForCell
 * 
 * Returns the string or DOM node to be used as the tooltip for the given
 * cell. This implementation uses the cells getTooltip function if it
 * exists, or else it returns <convertValueToString> for the cell.
 * 
 * Example:
 * 
 * (code)
 * graph.getTooltipForCell = function(cell)
 * {
 *   return 'Hello, World!';
 * }
 * (end)
 * 
 * Replaces all tooltips with the string Hello, World!
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose tooltip should be returned.
 */
mxGraph.prototype.getTooltipForCell = function(cell)
{
\tvar tip = null;
\t
\tif (cell != null && cell.getTooltip != null)
\t{
\t\ttip = cell.getTooltip();
\t}
\telse
\t{
\t\ttip = this.convertValueToString(cell);
\t}
\t
\treturn tip;
};

/**
 * Function: getLinkForCell
 * 
 * Returns the string to be used as the link for the given cell. This
 * implementation returns null.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose tooltip should be returned.
 */
mxGraph.prototype.getLinkForCell = function(cell)
{
\treturn null;
};

/**
 * Function: getCursorForMouseEvent
 * 
 * Returns the cursor value to be used for the CSS of the shape for the
 * given event. This implementation calls <getCursorForCell>.
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> whose cursor should be returned.
 */
mxGraph.prototype.getCursorForMouseEvent = function(me)
{
\treturn this.getCursorForCell(me.getCell());
};

/**
 * Function: getCursorForCell
 * 
 * Returns the cursor value to be used for the CSS of the shape for the
 * given cell. This implementation returns null.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose cursor should be returned.
 */
mxGraph.prototype.getCursorForCell = function(cell)
{
\treturn null;
};

/**
 * Function: getStartSize
 * 
 * Returns the start size of the given swimlane, that is, the width or
 * height of the part that contains the title, depending on the
 * horizontal style. The return value is an <mxRectangle> with either
 * width or height set as appropriate.
 * 
 * Parameters:
 * 
 * swimlane - <mxCell> whose start size should be returned.
 * ignoreState - Optional boolean that specifies if cell state should be ignored.
 */
mxGraph.prototype.getStartSize = function(swimlane, ignoreState)
{
\tvar result = new mxRectangle();
\tvar style = this.getCurrentCellStyle(swimlane, ignoreState);
\tvar size = parseInt(mxUtils.getValue(style,
\t\tmxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
\t
\tif (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
\t{
\t\tresult.height = size;
\t}
\telse
\t{
\t\tresult.width = size;
\t}
\t
\treturn result;
};

/**
 * Function: getSwimlaneDirection
 * 
 * Returns the direction for the given swimlane style.
 */
mxGraph.prototype.getSwimlaneDirection = function(style)
{
\tvar dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
\tvar flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
\tvar flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
\tvar h = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true);
\tvar n = (h) ? 0 : 3;
\t
\tif (dir == mxConstants.DIRECTION_NORTH)
\t{
\t\tn--;
\t}
\telse if (dir == mxConstants.DIRECTION_WEST)
\t{
\t\tn += 2;
\t}
\telse if (dir == mxConstants.DIRECTION_SOUTH)
\t{
\t\tn += 1;
\t}
\t
\tvar mod = mxUtils.mod(n, 2);
\t
\tif (flipH && mod == 1)
\t{
\t\tn += 2;
\t}
\t
\tif (flipV && mod == 0)
\t{
\t\tn += 2;
\t}
\t
\treturn [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST,
\t\tmxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST]
\t\t[mxUtils.mod(n, 4)];
};

/**
 * Function: getActualStartSize
 * 
 * Returns the actual start size of the given swimlane taking into account
 * direction and horizontal and vertial flip styles. The start size is
 * returned as an <mxRectangle> where top, left, bottom, right start sizes
 * are returned as x, y, height and width, respectively.
 * 
 * Parameters:
 * 
 * swimlane - <mxCell> whose start size should be returned.
 * ignoreState - Optional boolean that specifies if cell state should be ignored.
 */
mxGraph.prototype.getActualStartSize = function(swimlane, ignoreState)
{
\tvar result = new mxRectangle();
\t
\tif (this.isSwimlane(swimlane, ignoreState))
\t{
\t\tvar style = this.getCurrentCellStyle(swimlane, ignoreState);
\t\tvar size = parseInt(mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE,
\t\t\tmxConstants.DEFAULT_STARTSIZE));
\t\tvar dir = this.getSwimlaneDirection(style);
\t\t
\t\tif (dir == mxConstants.DIRECTION_NORTH)
\t\t{
\t\t\tresult.y = size;
\t\t}
\t\telse if (dir == mxConstants.DIRECTION_WEST)
\t\t{
\t\t\tresult.x = size;
\t\t}
\t\telse if (dir == mxConstants.DIRECTION_SOUTH)
\t\t{
\t\t\tresult.height = size;
\t\t}
\t\telse
\t\t{
\t\t\tresult.width = size;
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getImage
 * 
 * Returns the image URL for the given cell state. This implementation
 * returns the value stored under <mxConstants.STYLE_IMAGE> in the cell
 * style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose image URL should be returned.
 */
mxGraph.prototype.getImage = function(state)
{
\treturn (state != null && state.style != null) ? state.style[mxConstants.STYLE_IMAGE] : null;
};

/**
 * Function: isTransparentState
 * 
 * Returns true if the given state has no stroke- or fillcolor and no image.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to check.
 */
mxGraph.prototype.isTransparentState = function(state)
{
\tvar result = false;
\t
\tif (state != null)
\t{
\t\tvar stroke = mxUtils.getValue(state.style, mxConstants.STYLE_STROKECOLOR, mxConstants.NONE);
\t\tvar fill = mxUtils.getValue(state.style, mxConstants.STYLE_FILLCOLOR, mxConstants.NONE);
\t\t
\t\tresult = stroke == mxConstants.NONE && fill == mxConstants.NONE && this.getImage(state) == null;
\t\t
\t}
\t
\treturn result;
};

/**
 * Function: getVerticalAlign
 * 
 * Returns the vertical alignment for the given cell state. This
 * implementation returns the value stored under
 * <mxConstants.STYLE_VERTICAL_ALIGN> in the cell style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose vertical alignment should be
 * returned.
 */
mxGraph.prototype.getVerticalAlign = function(state)
{
\treturn (state != null && state.style != null) ?
\t\t(state.style[mxConstants.STYLE_VERTICAL_ALIGN] ||
\t\tmxConstants.ALIGN_MIDDLE) : null;
};

/**
 * Function: getIndicatorColor
 * 
 * Returns the indicator color for the given cell state. This
 * implementation returns the value stored under
 * <mxConstants.STYLE_INDICATOR_COLOR> in the cell style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose indicator color should be
 * returned.
 */
mxGraph.prototype.getIndicatorColor = function(state)
{
\treturn (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_COLOR] : null;
};

/**
 * Function: getIndicatorGradientColor
 * 
 * Returns the indicator gradient color for the given cell state. This
 * implementation returns the value stored under
 * <mxConstants.STYLE_INDICATOR_GRADIENTCOLOR> in the cell style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose indicator gradient color should be
 * returned.
 */
mxGraph.prototype.getIndicatorGradientColor = function(state)
{
\treturn (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_GRADIENTCOLOR] : null;
};

/**
 * Function: getIndicatorShape
 * 
 * Returns the indicator shape for the given cell state. This
 * implementation returns the value stored under
 * <mxConstants.STYLE_INDICATOR_SHAPE> in the cell style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose indicator shape should be returned.
 */
mxGraph.prototype.getIndicatorShape = function(state)
{
\treturn (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_SHAPE] : null;
};

/**
 * Function: getIndicatorImage
 * 
 * Returns the indicator image for the given cell state. This
 * implementation returns the value stored under
 * <mxConstants.STYLE_INDICATOR_IMAGE> in the cell style.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose indicator image should be returned.
 */
mxGraph.prototype.getIndicatorImage = function(state)
{
\treturn (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_IMAGE] : null;
};

/**
 * Function: getBorder
 * 
 * Returns the value of <border>.
 */
mxGraph.prototype.getBorder = function()
{
\treturn this.border;
};

/**
 * Function: setBorder
 * 
 * Sets the value of <border>.
 * 
 * Parameters:
 * 
 * value - Positive integer that represents the border to be used.
 */
mxGraph.prototype.setBorder = function(value)
{
\tthis.border = value;
};

/**
 * Function: isSwimlane
 * 
 * Returns true if the given cell is a swimlane in the graph. A swimlane is
 * a container cell with some specific behaviour. This implementation
 * checks if the shape associated with the given cell is a <mxSwimlane>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be checked.
 * ignoreState - Optional boolean that specifies if the cell state should be ignored.
 */
mxGraph.prototype.isSwimlane = function(cell, ignoreState)
{
\tif (cell != null && this.model.getParent(cell) != this.model.getRoot() &&
\t\t!this.model.isEdge(cell))
\t{
\t\treturn this.getCurrentCellStyle(cell, ignoreState)
\t\t\t[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_SWIMLANE;
\t}
\t
\treturn false;
};

/**
 * Group: Graph behaviour
 */

/**
 * Function: isResizeContainer
 * 
 * Returns <resizeContainer>.
 */
mxGraph.prototype.isResizeContainer = function()
{
\treturn this.resizeContainer;
};

/**
 * Function: setResizeContainer
 * 
 * Sets <resizeContainer>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the container should be resized.
 */
mxGraph.prototype.setResizeContainer = function(value)
{
\tthis.resizeContainer = value;
};

/**
 * Function: isEnabled
 * 
 * Returns true if the graph is <enabled>.
 */
mxGraph.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Specifies if the graph should allow any interactions. This
 * implementation updates <enabled>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should be enabled.
 */
mxGraph.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: isEscapeEnabled
 * 
 * Returns <escapeEnabled>.
 */
mxGraph.prototype.isEscapeEnabled = function()
{
\treturn this.escapeEnabled;
};

/**
 * Function: setEscapeEnabled
 * 
 * Sets <escapeEnabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean indicating if escape should be enabled.
 */
mxGraph.prototype.setEscapeEnabled = function(value)
{
\tthis.escapeEnabled = value;
};

/**
 * Function: isInvokesStopCellEditing
 * 
 * Returns <invokesStopCellEditing>.
 */
mxGraph.prototype.isInvokesStopCellEditing = function()
{
\treturn this.invokesStopCellEditing;
};

/**
 * Function: setInvokesStopCellEditing
 * 
 * Sets <invokesStopCellEditing>.
 */
mxGraph.prototype.setInvokesStopCellEditing = function(value)
{
\tthis.invokesStopCellEditing = value;
};

/**
 * Function: isEnterStopsCellEditing
 * 
 * Returns <enterStopsCellEditing>.
 */
mxGraph.prototype.isEnterStopsCellEditing = function()
{
\treturn this.enterStopsCellEditing;
};

/**
 * Function: setEnterStopsCellEditing
 * 
 * Sets <enterStopsCellEditing>.
 */
mxGraph.prototype.setEnterStopsCellEditing = function(value)
{
\tthis.enterStopsCellEditing = value;
};

/**
 * Function: isCellLocked
 * 
 * Returns true if the given cell may not be moved, sized, bended,
 * disconnected, edited or selected. This implementation returns true for
 * all vertices with a relative geometry if <locked> is false.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose locked state should be returned.
 */
mxGraph.prototype.isCellLocked = function(cell)
{
\tvar geometry = this.model.getGeometry(cell);
\t
\treturn this.isCellsLocked() || (geometry != null && this.model.isVertex(cell) && geometry.relative);
};

/**
 * Function: isCellsLocked
 * 
 * Returns true if the given cell may not be moved, sized, bended,
 * disconnected, edited or selected. This implementation returns true for
 * all vertices with a relative geometry if <locked> is false.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose locked state should be returned.
 */
mxGraph.prototype.isCellsLocked = function()
{
\treturn this.cellsLocked;
};

/**
 * Function: setCellsLocked
 * 
 * Sets if any cell may be moved, sized, bended, disconnected, edited or
 * selected.
 * 
 * Parameters:
 * 
 * value - Boolean that defines the new value for <cellsLocked>.
 */
mxGraph.prototype.setCellsLocked = function(value)
{
\tthis.cellsLocked = value;
};

/**
 * Function: getCloneableCells
 * 
 * Returns the cells which may be exported in the given array of cells.
 */
mxGraph.prototype.getCloneableCells = function(cells)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.isCellCloneable(cell);
\t}));
};

/**
 * Function: isCellCloneable
 * 
 * Returns true if the given cell is cloneable. This implementation returns
 * <isCellsCloneable> for all cells unless a cell style specifies
 * <mxConstants.STYLE_CLONEABLE> to be 0. 
 * 
 * Parameters:
 * 
 * cell - Optional <mxCell> whose cloneable state should be returned.
 */
mxGraph.prototype.isCellCloneable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);

\treturn this.isCellsCloneable() && style[mxConstants.STYLE_CLONEABLE] != 0;
};

/**
 * Function: isCellsCloneable
 * 
 * Returns <cellsCloneable>, that is, if the graph allows cloning of cells
 * by using control-drag.
 */
mxGraph.prototype.isCellsCloneable = function()
{
\treturn this.cellsCloneable;
};

/**
 * Function: setCellsCloneable
 * 
 * Specifies if the graph should allow cloning of cells by holding down the
 * control key while cells are being moved. This implementation updates
 * <cellsCloneable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should be cloneable.
 */
mxGraph.prototype.setCellsCloneable = function(value)
{
\tthis.cellsCloneable = value;
};

/**
 * Function: getExportableCells
 * 
 * Returns the cells which may be exported in the given array of cells.
 */
mxGraph.prototype.getExportableCells = function(cells)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.canExportCell(cell);
\t}));
};

/**
 * Function: canExportCell
 * 
 * Returns true if the given cell may be exported to the clipboard. This
 * implementation returns <exportEnabled> for all cells.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the cell to be exported.
 */
mxGraph.prototype.canExportCell = function(cell)
{
\treturn this.exportEnabled;
};

/**
 * Function: getImportableCells
 * 
 * Returns the cells which may be imported in the given array of cells.
 */
mxGraph.prototype.getImportableCells = function(cells)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.canImportCell(cell);
\t}));
};

/**
 * Function: canImportCell
 * 
 * Returns true if the given cell may be imported from the clipboard.
 * This implementation returns <importEnabled> for all cells.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the cell to be imported.
 */
mxGraph.prototype.canImportCell = function(cell)
{
\treturn this.importEnabled;
};

/**
 * Function: isCellSelectable
 *
 * Returns true if the given cell is selectable. This implementation
 * returns <cellsSelectable>.
 * 
 * To add a new style for making cells (un)selectable, use the following code.
 * 
 * (code)
 * mxGraph.prototype.isCellSelectable = function(cell)
 * {
 *   var style = this.getCurrentCellStyle(cell);
 *   
 *   return this.isCellsSelectable() && !this.isCellLocked(cell) && style['selectable'] != 0;
 * };
 * (end)
 * 
 * You can then use the new style as shown in this example.
 * 
 * (code)
 * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'selectable=0');
 * (end)
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose selectable state should be returned.
 */
mxGraph.prototype.isCellSelectable = function(cell)
{
\treturn this.isCellsSelectable();
};

/**
 * Function: isCellsSelectable
 *
 * Returns <cellsSelectable>.
 */
mxGraph.prototype.isCellsSelectable = function()
{
\treturn this.cellsSelectable;
};

/**
 * Function: setCellsSelectable
 *
 * Sets <cellsSelectable>.
 */
mxGraph.prototype.setCellsSelectable = function(value)
{
\tthis.cellsSelectable = value;
};

/**
 * Function: getDeletableCells
 * 
 * Returns the cells which may be exported in the given array of cells.
 */
mxGraph.prototype.getDeletableCells = function(cells)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.isCellDeletable(cell);
\t}));
};

/**
 * Function: isCellDeletable
 *
 * Returns true if the given cell is moveable. This returns
 * <cellsDeletable> for all given cells if a cells style does not specify
 * <mxConstants.STYLE_DELETABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose deletable state should be returned.
 */
mxGraph.prototype.isCellDeletable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.isCellsDeletable() && style[mxConstants.STYLE_DELETABLE] != 0;
};

/**
 * Function: isCellsDeletable
 *
 * Returns <cellsDeletable>.
 */
mxGraph.prototype.isCellsDeletable = function()
{
\treturn this.cellsDeletable;
};

/**
 * Function: setCellsDeletable
 * 
 * Sets <cellsDeletable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should allow deletion of cells.
 */
mxGraph.prototype.setCellsDeletable = function(value)
{
\tthis.cellsDeletable = value;
};

/**
 * Function: isLabelMovable
 *
 * Returns true if the given edges's label is moveable. This returns
 * <movable> for all given cells if <isLocked> does not return true
 * for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose label should be moved.
 */
mxGraph.prototype.isLabelMovable = function(cell)
{
\treturn !this.isCellLocked(cell) &&
\t\t((this.model.isEdge(cell) && this.edgeLabelsMovable) ||
\t\t(this.model.isVertex(cell) && this.vertexLabelsMovable));
};

/**
 * Function: isCellRotatable
 *
 * Returns true if the given cell is rotatable. This returns true for the given
 * cell if its style does not specify <mxConstants.STYLE_ROTATABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose rotatable state should be returned.
 */
mxGraph.prototype.isCellRotatable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn style[mxConstants.STYLE_ROTATABLE] != 0;
};

/**
 * Function: getMovableCells
 * 
 * Returns the cells which are movable in the given array of cells.
 */
mxGraph.prototype.getMovableCells = function(cells)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.isCellMovable(cell);
\t}));
};

/**
 * Function: isCellMovable
 *
 * Returns true if the given cell is moveable. This returns <cellsMovable>
 * for all given cells if <isCellLocked> does not return true for the given
 * cell and its style does not specify <mxConstants.STYLE_MOVABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose movable state should be returned.
 */
mxGraph.prototype.isCellMovable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.isCellsMovable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0;
};

/**
 * Function: isCellsMovable
 *
 * Returns <cellsMovable>.
 */
mxGraph.prototype.isCellsMovable = function()
{
\treturn this.cellsMovable;
};

/**
 * Function: setCellsMovable
 * 
 * Specifies if the graph should allow moving of cells. This implementation
 * updates <cellsMsovable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should allow moving of cells.
 */
mxGraph.prototype.setCellsMovable = function(value)
{
\tthis.cellsMovable = value;
};

/**
 * Function: isGridEnabled
 *
 * Returns <gridEnabled> as a boolean.
 */
mxGraph.prototype.isGridEnabled = function()
{
\treturn this.gridEnabled;
};

/**
 * Function: setGridEnabled
 * 
 * Specifies if the grid should be enabled.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the grid should be enabled.
 */
mxGraph.prototype.setGridEnabled = function(value)
{
\tthis.gridEnabled = value;
};

/**
 * Function: isPortsEnabled
 *
 * Returns <portsEnabled> as a boolean.
 */
mxGraph.prototype.isPortsEnabled = function()
{
\treturn this.portsEnabled;
};

/**
 * Function: setPortsEnabled
 * 
 * Specifies if the ports should be enabled.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the ports should be enabled.
 */
mxGraph.prototype.setPortsEnabled = function(value)
{
\tthis.portsEnabled = value;
};

/**
 * Function: getGridSize
 *
 * Returns <gridSize>.
 */
mxGraph.prototype.getGridSize = function()
{
\treturn this.gridSize;
};

/**
 * Function: setGridSize
 * 
 * Sets <gridSize>.
 */
mxGraph.prototype.setGridSize = function(value)
{
\tthis.gridSize = value;
};

/**
 * Function: getTolerance
 *
 * Returns <tolerance>.
 */
mxGraph.prototype.getTolerance = function()
{
\treturn this.tolerance;
};

/**
 * Function: setTolerance
 * 
 * Sets <tolerance>.
 */
mxGraph.prototype.setTolerance = function(value)
{
\tthis.tolerance = value;
};

/**
 * Function: isVertexLabelsMovable
 *
 * Returns <vertexLabelsMovable>.
 */
mxGraph.prototype.isVertexLabelsMovable = function()
{
\treturn this.vertexLabelsMovable;
};

/**
 * Function: setVertexLabelsMovable
 * 
 * Sets <vertexLabelsMovable>.
 */
mxGraph.prototype.setVertexLabelsMovable = function(value)
{
\tthis.vertexLabelsMovable = value;
};

/**
 * Function: isEdgeLabelsMovable
 *
 * Returns <edgeLabelsMovable>.
 */
mxGraph.prototype.isEdgeLabelsMovable = function()
{
\treturn this.edgeLabelsMovable;
};

/**
 * Function: isEdgeLabelsMovable
 * 
 * Sets <edgeLabelsMovable>.
 */
mxGraph.prototype.setEdgeLabelsMovable = function(value)
{
\tthis.edgeLabelsMovable = value;
};

/**
 * Function: isSwimlaneNesting
 *
 * Returns <swimlaneNesting> as a boolean.
 */
mxGraph.prototype.isSwimlaneNesting = function()
{
\treturn this.swimlaneNesting;
};

/**
 * Function: setSwimlaneNesting
 * 
 * Specifies if swimlanes can be nested by drag and drop. This is only
 * taken into account if dropEnabled is true.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if swimlanes can be nested.
 */
mxGraph.prototype.setSwimlaneNesting = function(value)
{
\tthis.swimlaneNesting = value;
};

/**
 * Function: isSwimlaneSelectionEnabled
 *
 * Returns <swimlaneSelectionEnabled> as a boolean.
 */
mxGraph.prototype.isSwimlaneSelectionEnabled = function()
{
\treturn this.swimlaneSelectionEnabled;
};

/**
 * Function: setSwimlaneSelectionEnabled
 * 
 * Specifies if swimlanes should be selected if the mouse is released
 * over their content area.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if swimlanes content areas
 * should be selected when the mouse is released over them.
 */
mxGraph.prototype.setSwimlaneSelectionEnabled = function(value)
{
\tthis.swimlaneSelectionEnabled = value;
};

/**
 * Function: isMultigraph
 *
 * Returns <multigraph> as a boolean.
 */
mxGraph.prototype.isMultigraph = function()
{
\treturn this.multigraph;
};

/**
 * Function: setMultigraph
 * 
 * Specifies if the graph should allow multiple connections between the
 * same pair of vertices.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph allows multiple connections
 * between the same pair of vertices.
 */
mxGraph.prototype.setMultigraph = function(value)
{
\tthis.multigraph = value;
};

/**
 * Function: isAllowLoops
 *
 * Returns <allowLoops> as a boolean.
 */
mxGraph.prototype.isAllowLoops = function()
{
\treturn this.allowLoops;
};

/**
 * Function: setAllowDanglingEdges
 * 
 * Specifies if dangling edges are allowed, that is, if edges are allowed
 * that do not have a source and/or target terminal defined.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if dangling edges are allowed.
 */
mxGraph.prototype.setAllowDanglingEdges = function(value)
{
\tthis.allowDanglingEdges = value;
};

/**
 * Function: isAllowDanglingEdges
 *
 * Returns <allowDanglingEdges> as a boolean.
 */
mxGraph.prototype.isAllowDanglingEdges = function()
{
\treturn this.allowDanglingEdges;
};

/**
 * Function: setConnectableEdges
 * 
 * Specifies if edges should be connectable.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if edges should be connectable.
 */
mxGraph.prototype.setConnectableEdges = function(value)
{
\tthis.connectableEdges = value;
};

/**
 * Function: isConnectableEdges
 *
 * Returns <connectableEdges> as a boolean.
 */
mxGraph.prototype.isConnectableEdges = function()
{
\treturn this.connectableEdges;
};

/**
 * Function: setCloneInvalidEdges
 * 
 * Specifies if edges should be inserted when cloned but not valid wrt.
 * <getEdgeValidationError>. If false such edges will be silently ignored.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if cloned invalid edges should be
 * inserted into the graph or ignored.
 */
mxGraph.prototype.setCloneInvalidEdges = function(value)
{
\tthis.cloneInvalidEdges = value;
};

/**
 * Function: isCloneInvalidEdges
 *
 * Returns <cloneInvalidEdges> as a boolean.
 */
mxGraph.prototype.isCloneInvalidEdges = function()
{
\treturn this.cloneInvalidEdges;
};

/**
 * Function: setAllowLoops
 * 
 * Specifies if loops are allowed.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if loops are allowed.
 */
mxGraph.prototype.setAllowLoops = function(value)
{
\tthis.allowLoops = value;
};

/**
 * Function: isDisconnectOnMove
 *
 * Returns <disconnectOnMove> as a boolean.
 */
mxGraph.prototype.isDisconnectOnMove = function()
{
\treturn this.disconnectOnMove;
};

/**
 * Function: setDisconnectOnMove
 * 
 * Specifies if edges should be disconnected when moved. (Note: Cloned
 * edges are always disconnected.)
 * 
 * Parameters:
 * 
 * value - Boolean indicating if edges should be disconnected
 * when moved.
 */
mxGraph.prototype.setDisconnectOnMove = function(value)
{
\tthis.disconnectOnMove = value;
};

/**
 * Function: isDropEnabled
 *
 * Returns <dropEnabled> as a boolean.
 */
mxGraph.prototype.isDropEnabled = function()
{
\treturn this.dropEnabled;
};

/**
 * Function: setDropEnabled
 * 
 * Specifies if the graph should allow dropping of cells onto or into other
 * cells.
 * 
 * Parameters:
 * 
 * dropEnabled - Boolean indicating if the graph should allow dropping
 * of cells into other cells.
 */
mxGraph.prototype.setDropEnabled = function(value)
{
\tthis.dropEnabled = value;
};

/**
 * Function: isSplitEnabled
 *
 * Returns <splitEnabled> as a boolean.
 */
mxGraph.prototype.isSplitEnabled = function()
{
\treturn this.splitEnabled;
};

/**
 * Function: setSplitEnabled
 * 
 * Specifies if the graph should allow dropping of cells onto or into other
 * cells.
 * 
 * Parameters:
 * 
 * dropEnabled - Boolean indicating if the graph should allow dropping
 * of cells into other cells.
 */
mxGraph.prototype.setSplitEnabled = function(value)
{
\tthis.splitEnabled = value;
};

/**
 * Function: isCellResizable
 *
 * Returns true if the given cell is resizable. This returns
 * <cellsResizable> for all given cells if <isCellLocked> does not return
 * true for the given cell and its style does not specify
 * <mxConstants.STYLE_RESIZABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose resizable state should be returned.
 */
mxGraph.prototype.isCellResizable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);

\treturn this.isCellsResizable() && !this.isCellLocked(cell) &&
\t\tmxUtils.getValue(style, mxConstants.STYLE_RESIZABLE, '1') != '0';
};

/**
 * Function: isCellsResizable
 *
 * Returns <cellsResizable>.
 */
mxGraph.prototype.isCellsResizable = function()
{
\treturn this.cellsResizable;
};

/**
 * Function: setCellsResizable
 * 
 * Specifies if the graph should allow resizing of cells. This
 * implementation updates <cellsResizable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should allow resizing of
 * cells.
 */
mxGraph.prototype.setCellsResizable = function(value)
{
\tthis.cellsResizable = value;
};

/**
 * Function: isTerminalPointMovable
 *
 * Returns true if the given terminal point is movable. This is independent
 * from <isCellConnectable> and <isCellDisconnectable> and controls if terminal
 * points can be moved in the graph if the edge is not connected. Note that it
 * is required for this to return true to connect unconnected edges. This
 * implementation returns true.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose terminal point should be moved.
 * source - Boolean indicating if the source or target terminal should be moved.
 */
mxGraph.prototype.isTerminalPointMovable = function(cell, source)
{
\treturn true;
};

/**
 * Function: isCellBendable
 *
 * Returns true if the given cell is bendable. This returns <cellsBendable>
 * for all given cells if <isLocked> does not return true for the given
 * cell and its style does not specify <mxConstants.STYLE_BENDABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose bendable state should be returned.
 */
mxGraph.prototype.isCellBendable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.isCellsBendable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_BENDABLE] != 0;
};

/**
 * Function: isCellsBendable
 *
 * Returns <cellsBenadable>.
 */
mxGraph.prototype.isCellsBendable = function()
{
\treturn this.cellsBendable;
};

/**
 * Function: setCellsBendable
 * 
 * Specifies if the graph should allow bending of edges. This
 * implementation updates <bendable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should allow bending of
 * edges.
 */
mxGraph.prototype.setCellsBendable = function(value)
{
\tthis.cellsBendable = value;
};

/**
 * Function: isCellEditable
 *
 * Returns true if the given cell is editable. This returns <cellsEditable> for
 * all given cells if <isCellLocked> does not return true for the given cell
 * and its style does not specify <mxConstants.STYLE_EDITABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose editable state should be returned.
 */
mxGraph.prototype.isCellEditable = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.isCellsEditable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_EDITABLE] != 0;
};

/**
 * Function: isCellsEditable
 *
 * Returns <cellsEditable>.
 */
mxGraph.prototype.isCellsEditable = function()
{
\treturn this.cellsEditable;
};

/**
 * Function: setCellsEditable
 * 
 * Specifies if the graph should allow in-place editing for cell labels.
 * This implementation updates <cellsEditable>.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if the graph should allow in-place
 * editing.
 */
mxGraph.prototype.setCellsEditable = function(value)
{
\tthis.cellsEditable = value;
};

/**
 * Function: isCellDisconnectable
 *
 * Returns true if the given cell is disconnectable from the source or
 * target terminal. This returns <isCellsDisconnectable> for all given
 * cells if <isCellLocked> does not return true for the given cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose disconnectable state should be returned.
 * terminal - <mxCell> that represents the source or target terminal.
 * source - Boolean indicating if the source or target terminal is to be
 * disconnected.
 */
mxGraph.prototype.isCellDisconnectable = function(cell, terminal, source)
{
\treturn this.isCellsDisconnectable() && !this.isCellLocked(cell);
};

/**
 * Function: isCellsDisconnectable
 *
 * Returns <cellsDisconnectable>.
 */
mxGraph.prototype.isCellsDisconnectable = function()
{
\treturn this.cellsDisconnectable;
};

/**
 * Function: setCellsDisconnectable
 *
 * Sets <cellsDisconnectable>.
 */
mxGraph.prototype.setCellsDisconnectable = function(value)
{
\tthis.cellsDisconnectable = value;
};

/**
 * Function: isValidSource
 * 
 * Returns true if the given cell is a valid source for new connections.
 * This implementation returns true for all non-null values and is
 * called by is called by <isValidConnection>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents a possible source or null.
 */
mxGraph.prototype.isValidSource = function(cell)
{
\treturn (cell == null && this.allowDanglingEdges) ||
\t\t(cell != null && (!this.model.isEdge(cell) ||
\t\tthis.connectableEdges) && this.isCellConnectable(cell));
};
\t
/**
 * Function: isValidTarget
 * 
 * Returns <isValidSource> for the given cell. This is called by
 * <isValidConnection>.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents a possible target or null.
 */
mxGraph.prototype.isValidTarget = function(cell)
{
\treturn this.isValidSource(cell);
};

/**
 * Function: isValidConnection
 * 
 * Returns true if the given target cell is a valid target for source.
 * This is a boolean implementation for not allowing connections between
 * certain pairs of vertices and is called by <getEdgeValidationError>.
 * This implementation returns true if <isValidSource> returns true for
 * the source and <isValidTarget> returns true for the target.
 * 
 * Parameters:
 * 
 * source - <mxCell> that represents the source cell.
 * target - <mxCell> that represents the target cell.
 */
mxGraph.prototype.isValidConnection = function(source, target)
{
\treturn this.isValidSource(source) && this.isValidTarget(target);
};

/**
 * Function: setConnectable
 * 
 * Specifies if the graph should allow new connections. This implementation
 * updates <mxConnectionHandler.enabled> in <connectionHandler>.
 * 
 * Parameters:
 * 
 * connectable - Boolean indicating if new connections should be allowed.
 */
mxGraph.prototype.setConnectable = function(connectable)
{
\tthis.connectionHandler.setEnabled(connectable);
};
\t
/**
 * Function: isConnectable
 * 
 * Returns true if the <connectionHandler> is enabled.
 */
mxGraph.prototype.isConnectable = function()
{
\treturn this.connectionHandler.isEnabled();
};

/**
 * Function: setTooltips
 * 
 * Specifies if tooltips should be enabled. This implementation updates
 * <mxTooltipHandler.enabled> in <tooltipHandler>.
 * 
 * Parameters:
 * 
 * enabled - Boolean indicating if tooltips should be enabled.
 */
mxGraph.prototype.setTooltips = function (enabled)
{
\tthis.tooltipHandler.setEnabled(enabled);
};

/**
 * Function: setPanning
 * 
 * Specifies if panning should be enabled. This implementation updates
 * <mxPanningHandler.panningEnabled> in <panningHandler>.
 * 
 * Parameters:
 * 
 * enabled - Boolean indicating if panning should be enabled.
 */
mxGraph.prototype.setPanning = function(enabled)
{
\tthis.panningHandler.panningEnabled = enabled;
};

/**
 * Function: isEditing
 * 
 * Returns true if the given cell is currently being edited.
 * If no cell is specified then this returns true if any
 * cell is currently being edited.
 *
 * Parameters:
 * 
 * cell - <mxCell> that should be checked.
 */
mxGraph.prototype.isEditing = function(cell)
{
\tif (this.cellEditor != null)
\t{
\t\tvar editingCell = this.cellEditor.getEditingCell();
\t\t
\t\treturn (cell == null) ? editingCell != null : cell == editingCell;
\t}
\t
\treturn false;
};

/**
 * Function: isAutoSizeCell
 * 
 * Returns true if the size of the given cell should automatically be
 * updated after a change of the label. This implementation returns
 * <autoSizeCells> or checks if the cell style does specify
 * <mxConstants.STYLE_AUTOSIZE> to be 1.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that should be resized.
 */
mxGraph.prototype.isAutoSizeCell = function(cell)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.isAutoSizeCells() || style[mxConstants.STYLE_AUTOSIZE] == 1;
};

/**
 * Function: isAutoSizeCells
 * 
 * Returns <autoSizeCells>.
 */
mxGraph.prototype.isAutoSizeCells = function()
{
\treturn this.autoSizeCells;
};

/**
 * Function: setAutoSizeCells
 * 
 * Specifies if cell sizes should be automatically updated after a label
 * change. This implementation sets <autoSizeCells> to the given parameter.
 * To update the size of cells when the cells are added, set
 * <autoSizeCellsOnAdd> to true.
 * 
 * Parameters:
 * 
 * value - Boolean indicating if cells should be resized
 * automatically.
 */
mxGraph.prototype.setAutoSizeCells = function(value)
{
\tthis.autoSizeCells = value;
};

/**
 * Function: isExtendParent
 * 
 * Returns true if the parent of the given cell should be extended if the
 * child has been resized so that it overlaps the parent. This
 * implementation returns <isExtendParents> if the cell is not an edge.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that has been resized.
 */
mxGraph.prototype.isExtendParent = function(cell)
{
\treturn !this.getModel().isEdge(cell) && this.isExtendParents();
};

/**
 * Function: isExtendParents
 * 
 * Returns <extendParents>.
 */
mxGraph.prototype.isExtendParents = function()
{
\treturn this.extendParents;
};

/**
 * Function: setExtendParents
 * 
 * Sets <extendParents>.
 * 
 * Parameters:
 * 
 * value - New boolean value for <extendParents>.
 */
mxGraph.prototype.setExtendParents = function(value)
{
\tthis.extendParents = value;
};

/**
 * Function: isExtendParentsOnAdd
 * 
 * Returns <extendParentsOnAdd>.
 */
mxGraph.prototype.isExtendParentsOnAdd = function(cell)
{
\treturn this.extendParentsOnAdd;
};

/**
 * Function: setExtendParentsOnAdd
 * 
 * Sets <extendParentsOnAdd>.
 * 
 * Parameters:
 * 
 * value - New boolean value for <extendParentsOnAdd>.
 */
mxGraph.prototype.setExtendParentsOnAdd = function(value)
{
\tthis.extendParentsOnAdd = value;
};

/**
 * Function: isExtendParentsOnMove
 * 
 * Returns <extendParentsOnMove>.
 */
mxGraph.prototype.isExtendParentsOnMove = function()
{
\treturn this.extendParentsOnMove;
};

/**
 * Function: setExtendParentsOnMove
 * 
 * Sets <extendParentsOnMove>.
 * 
 * Parameters:
 * 
 * value - New boolean value for <extendParentsOnAdd>.
 */
mxGraph.prototype.setExtendParentsOnMove = function(value)
{
\tthis.extendParentsOnMove = value;
};

/**
 * Function: isRecursiveResize
 * 
 * Returns <recursiveResize>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that is being resized.
 */
mxGraph.prototype.isRecursiveResize = function(state)
{
\treturn this.recursiveResize;
};

/**
 * Function: setRecursiveResize
 * 
 * Sets <recursiveResize>.
 * 
 * Parameters:
 * 
 * value - New boolean value for <recursiveResize>.
 */
mxGraph.prototype.setRecursiveResize = function(value)
{
\tthis.recursiveResize = value;
};

/**
 * Function: isConstrainChild
 * 
 * Returns true if the given cell should be kept inside the bounds of its
 * parent according to the rules defined by <getOverlap> and
 * <isAllowOverlapParent>. This implementation returns false for all children
 * of edges and <isConstrainChildren> otherwise.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that should be constrained.
 */
mxGraph.prototype.isConstrainChild = function(cell)
{
\treturn this.isConstrainChildren() && !this.getModel().isEdge(this.getModel().getParent(cell));
};

/**
 * Function: isConstrainChildren
 * 
 * Returns <constrainChildren>.
 */
mxGraph.prototype.isConstrainChildren = function()
{
\treturn this.constrainChildren;
};

/**
 * Function: setConstrainChildren
 * 
 * Sets <constrainChildren>.
 */
mxGraph.prototype.setConstrainChildren = function(value)
{
\tthis.constrainChildren = value;
};

/**
 * Function: isConstrainRelativeChildren
 * 
 * Returns <constrainRelativeChildren>.
 */
mxGraph.prototype.isConstrainRelativeChildren = function()
{
\treturn this.constrainRelativeChildren;
};

/**
 * Function: setConstrainRelativeChildren
 * 
 * Sets <constrainRelativeChildren>.
 */
mxGraph.prototype.setConstrainRelativeChildren = function(value)
{
\tthis.constrainRelativeChildren = value;
};

/**
 * Function: isConstrainChildren
 * 
 * Returns <allowNegativeCoordinates>.
 */
mxGraph.prototype.isAllowNegativeCoordinates = function()
{
\treturn this.allowNegativeCoordinates;
};

/**
 * Function: setConstrainChildren
 * 
 * Sets <allowNegativeCoordinates>.
 */
mxGraph.prototype.setAllowNegativeCoordinates = function(value)
{
\tthis.allowNegativeCoordinates = value;
};

/**
 * Function: getOverlap
 * 
 * Returns a decimal number representing the amount of the width and height
 * of the given cell that is allowed to overlap its parent. A value of 0
 * means all children must stay inside the parent, 1 means the child is
 * allowed to be placed outside of the parent such that it touches one of
 * the parents sides. If <isAllowOverlapParent> returns false for the given
 * cell, then this method returns 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the overlap ratio should be returned.
 */
mxGraph.prototype.getOverlap = function(cell)
{
\treturn (this.isAllowOverlapParent(cell)) ? this.defaultOverlap : 0;
};
\t
/**
 * Function: isAllowOverlapParent
 * 
 * Returns true if the given cell is allowed to be placed outside of the
 * parents area.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the child to be checked.
 */
mxGraph.prototype.isAllowOverlapParent = function(cell)
{
\treturn false;
};

/**
 * Function: getFoldableCells
 * 
 * Returns the cells which are movable in the given array of cells.
 */
mxGraph.prototype.getFoldableCells = function(cells, collapse)
{
\treturn this.model.filterCells(cells, mxUtils.bind(this, function(cell)
\t{
\t\treturn this.isCellFoldable(cell, collapse);
\t}));
};

/**
 * Function: isCellFoldable
 * 
 * Returns true if the given cell is foldable. This implementation
 * returns true if the cell has at least one child and its style
 * does not specify <mxConstants.STYLE_FOLDABLE> to be 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose foldable state should be returned.
 */
mxGraph.prototype.isCellFoldable = function(cell, collapse)
{
\tvar style = this.getCurrentCellStyle(cell);
\t
\treturn this.model.getChildCount(cell) > 0 && style[mxConstants.STYLE_FOLDABLE] != 0;
};

/**
 * Function: isValidDropTarget
 *
 * Returns true if the given cell is a valid drop target for the specified
 * cells. If <splitEnabled> is true then this returns <isSplitTarget> for
 * the given arguments else it returns true if the cell is not collapsed
 * and its child count is greater than 0.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the possible drop target.
 * cells - <mxCells> that should be dropped into the target.
 * evt - Mouseevent that triggered the invocation.
 */
mxGraph.prototype.isValidDropTarget = function(cell, cells, evt)
{
\treturn cell != null && ((this.isSplitEnabled() &&
\t\tthis.isSplitTarget(cell, cells, evt)) || (!this.model.isEdge(cell) &&
\t\t(this.isSwimlane(cell) || (this.model.getChildCount(cell) > 0 &&
\t\t!this.isCellCollapsed(cell)))));
};

/**
 * Function: isSplitTarget
 *
 * Returns true if the given edge may be splitted into two edges with the
 * given cell as a new terminal between the two.
 * 
 * Parameters:
 * 
 * target - <mxCell> that represents the edge to be splitted.
 * cells - <mxCells> that should split the edge.
 * evt - Mouseevent that triggered the invocation.
 */
mxGraph.prototype.isSplitTarget = function(target, cells, evt)
{
\tif (this.model.isEdge(target) && cells != null && cells.length == 1 &&
\t\tthis.isCellConnectable(cells[0]) && this.getEdgeValidationError(target,
\t\t\tthis.model.getTerminal(target, true), cells[0]) == null)
\t{
\t\tvar src = this.model.getTerminal(target, true);
\t\tvar trg = this.model.getTerminal(target, false);

\t\treturn (!this.model.isAncestor(cells[0], src) &&
\t\t\t\t!this.model.isAncestor(cells[0], trg));
\t}

\treturn false;
};

/**
 * Function: getDropTarget
 * 
 * Returns the given cell if it is a drop target for the given cells or the
 * nearest ancestor that may be used as a drop target for the given cells.
 * If the given array contains a swimlane and <swimlaneNesting> is false
 * then this always returns null. If no cell is given, then the bottommost
 * swimlane at the location of the given event is returned.
 * 
 * This function should only be used if <isDropEnabled> returns true.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> which are to be dropped onto the target.
 * evt - Mouseevent for the drag and drop.
 * cell - <mxCell> that is under the mousepointer.
 * clone - Optional boolean to indicate of cells will be cloned.
 */
mxGraph.prototype.getDropTarget = function(cells, evt, cell, clone)
{
\tif (!this.isSwimlaneNesting())
\t{
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (this.isSwimlane(cells[i]))
\t\t\t{
\t\t\t\treturn null;
\t\t\t}
\t\t}
\t}

\tvar pt = mxUtils.convertPoint(this.container,
\t\tmxEvent.getClientX(evt), mxEvent.getClientY(evt));
\tpt.x -= this.panDx;
\tpt.y -= this.panDy;
\tvar swimlane = this.getSwimlaneAt(pt.x, pt.y);
\t
\tif (cell == null)
\t{
\t\tcell = swimlane;
\t}
\telse if (swimlane != null)
\t{
\t\t// Checks if the cell is an ancestor of the swimlane
\t\t// under the mouse and uses the swimlane in that case
\t\tvar tmp = this.model.getParent(swimlane);
\t\t
\t\twhile (tmp != null && this.isSwimlane(tmp) && tmp != cell)
\t\t{
\t\t\ttmp = this.model.getParent(tmp);
\t\t}
\t\t
\t\tif (tmp == cell)
\t\t{
\t\t\tcell = swimlane;
\t\t}
\t}
\t
\twhile (cell != null && !this.isValidDropTarget(cell, cells, evt) &&
\t\t!this.model.isLayer(cell))
\t{
\t\tcell = this.model.getParent(cell);
\t}
\t
\t// Checks if parent is dropped into child if not cloning
\tif (clone == null || !clone)
\t{
\t\tvar parent = cell;
\t\t
\t\twhile (parent != null && mxUtils.indexOf(cells, parent) < 0)
\t\t{
\t\t\tparent = this.model.getParent(parent);
\t\t}
\t}

\treturn (!this.model.isLayer(cell) && parent == null) ? cell : null;
};

/**
 * Group: Cell retrieval
 */

/**
 * Function: getDefaultParent
 * 
 * Returns <defaultParent> or <mxGraphView.currentRoot> or the first child
 * child of <mxGraphModel.root> if both are null. The value returned by
 * this function should be used as the parent for new cells (aka default
 * layer).
 */
mxGraph.prototype.getDefaultParent = function()
{
\tvar parent = this.getCurrentRoot();
\t
\tif (parent == null)
\t{
\t\tparent = this.defaultParent;
\t\t
\t\tif (parent == null)
\t\t{
\t\t\tvar root = this.model.getRoot();
\t\t\tparent = this.model.getChildAt(root, 0);
\t\t}
\t}
\t
\treturn parent;
};

/**
 * Function: setDefaultParent
 * 
 * Sets the <defaultParent> to the given cell. Set this to null to return
 * the first child of the root in getDefaultParent.
 */
mxGraph.prototype.setDefaultParent = function(cell)
{
\tthis.defaultParent = cell;
};

/**
 * Function: getSwimlane
 * 
 * Returns the nearest ancestor of the given cell which is a swimlane, or
 * the given cell, if it is itself a swimlane.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the ancestor swimlane should be returned.
 */
mxGraph.prototype.getSwimlane = function(cell)
{
\twhile (cell != null && !this.isSwimlane(cell))
\t{
\t\tcell = this.model.getParent(cell);
\t}
\t
\treturn cell;
};

/**
 * Function: getSwimlaneAt
 * 
 * Returns the bottom-most swimlane that intersects the given point (x, y)
 * in the cell hierarchy that starts at the given parent.
 * 
 * Parameters:
 * 
 * x - X-coordinate of the location to be checked.
 * y - Y-coordinate of the location to be checked.
 * parent - <mxCell> that should be used as the root of the recursion.
 * Default is <defaultParent>.
 */
mxGraph.prototype.getSwimlaneAt = function (x, y, parent)
{
\tif (parent == null)
\t{
\t\tparent = this.getCurrentRoot();
\t\t
\t\tif (parent == null)
\t\t{
\t\t\tparent = this.model.getRoot();
\t\t}
\t}
\t
\tif (parent != null)
\t{
\t\tvar childCount = this.model.getChildCount(parent);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = this.model.getChildAt(parent, i);
\t\t\t
\t\t\tif (child != null)
\t\t\t{
\t\t\t\tvar result = this.getSwimlaneAt(x, y, child);
\t\t\t\t
\t\t\t\tif (result != null)
\t\t\t\t{
\t\t\t\t\treturn result;
\t\t\t\t}
\t\t\t\telse if (this.isCellVisible(child) && this.isSwimlane(child))
\t\t\t\t{
\t\t\t\t\tvar state = this.view.getState(child);
\t\t\t\t\t
\t\t\t\t\tif (this.intersects(state, x, y))
\t\t\t\t\t{
\t\t\t\t\t\treturn child;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: getCellAt
 * 
 * Returns the bottom-most cell that intersects the given point (x, y) in
 * the cell hierarchy starting at the given parent. This will also return
 * swimlanes if the given location intersects the content area of the
 * swimlane. If this is not desired, then the <hitsSwimlaneContent> may be
 * used if the returned cell is a swimlane to determine if the location
 * is inside the content area or on the actual title of the swimlane.
 * 
 * Parameters:
 * 
 * x - X-coordinate of the location to be checked.
 * y - Y-coordinate of the location to be checked.
 * parent - <mxCell> that should be used as the root of the recursion.
 * Default is current root of the view or the root of the model.
 * vertices - Optional boolean indicating if vertices should be returned.
 * Default is true.
 * edges - Optional boolean indicating if edges should be returned. Default
 * is true.
 * ignoreFn - Optional function that returns true if cell should be ignored.
 * The function is passed the cell state and the x and y parameter.
 */
mxGraph.prototype.getCellAt = function(x, y, parent, vertices, edges, ignoreFn)
{
\tvertices = (vertices != null) ? vertices : true;
\tedges = (edges != null) ? edges : true;

\tif (parent == null)
\t{
\t\tparent = this.getCurrentRoot();
\t\t
\t\tif (parent == null)
\t\t{
\t\t\tparent = this.getModel().getRoot();
\t\t}
\t}

\tif (parent != null)
\t{
\t\tvar childCount = this.model.getChildCount(parent);
\t\t
\t\tfor (var i = childCount - 1; i >= 0; i--)
\t\t{
\t\t\tvar cell = this.model.getChildAt(parent, i);
\t\t\tvar result = this.getCellAt(x, y, cell, vertices, edges, ignoreFn);
\t\t\t
\t\t\tif (result != null)
\t\t\t{
\t\t\t\treturn result;
\t\t\t}
\t\t\telse if (this.isCellVisible(cell) && (edges && this.model.isEdge(cell) ||
\t\t\t\tvertices && this.model.isVertex(cell)))
\t\t\t{
\t\t\t\tvar state = this.view.getState(cell);

\t\t\t\tif (state != null && (ignoreFn == null || !ignoreFn(state, x, y)) &&
\t\t\t\t\tthis.intersects(state, x, y))
\t\t\t\t{
\t\t\t\t\treturn cell;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: intersects
 * 
 * Returns the bottom-most cell that intersects the given point (x, y) in
 * the cell hierarchy that starts at the given parent.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the cell state.
 * x - X-coordinate of the location to be checked.
 * y - Y-coordinate of the location to be checked.
 */
mxGraph.prototype.intersects = function(state, x, y)
{
\tif (state != null)
\t{
\t\tvar pts = state.absolutePoints;

\t\tif (pts != null)
\t\t{
\t\t\tvar t2 = this.tolerance * this.tolerance;
\t\t\tvar pt = pts[0];
\t\t\t
\t\t\tfor (var i = 1; i < pts.length; i++)
\t\t\t{
\t\t\t\tvar next = pts[i];
\t\t\t\tvar dist = mxUtils.ptSegDistSq(pt.x, pt.y, next.x, next.y, x, y);
\t\t\t\t
\t\t\t\tif (dist <= t2)
\t\t\t\t{
\t\t\t\t\treturn true;
\t\t\t\t}
\t\t\t\t
\t\t\t\tpt = next;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
\t\t\t
\t\t\tif (alpha != 0)
\t\t\t{
\t\t\t\tvar cos = Math.cos(-alpha);
\t\t\t\tvar sin = Math.sin(-alpha);
\t\t\t\tvar cx = new mxPoint(state.getCenterX(), state.getCenterY());
\t\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
\t\t\t\tx = pt.x;
\t\t\t\ty = pt.y;
\t\t\t}
\t\t\t
\t\t\tif (mxUtils.contains(state, x, y))
\t\t\t{
\t\t\t\treturn true;
\t\t\t}
\t\t}
\t}
\t
\treturn false;
};

/**
 * Function: hitsSwimlaneContent
 * 
 * Returns true if the given coordinate pair is inside the content
 * are of the given swimlane.
 * 
 * Parameters:
 * 
 * swimlane - <mxCell> that specifies the swimlane.
 * x - X-coordinate of the mouse event.
 * y - Y-coordinate of the mouse event.
 */
mxGraph.prototype.hitsSwimlaneContent = function(swimlane, x, y)
{
\tvar state = this.getView().getState(swimlane);
\tvar size = this.getStartSize(swimlane);
\t
\tif (state != null)
\t{
\t\tvar scale = this.getView().getScale();
\t\tx -= state.x;
\t\ty -= state.y;
\t\t
\t\tif (size.width > 0 && x > 0 && x > size.width * scale)
\t\t{
\t\t\treturn true;
\t\t}
\t\telse if (size.height > 0 && y > 0 && y > size.height * scale)
\t\t{
\t\t\treturn true;
\t\t}
\t}
\t
\treturn false;
};

/**
 * Function: getChildVertices
 * 
 * Returns the visible child vertices of the given parent.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be returned.
 */
mxGraph.prototype.getChildVertices = function(parent)
{
\treturn this.getChildCells(parent, true, false);
};
\t
/**
 * Function: getChildEdges
 * 
 * Returns the visible child edges of the given parent.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose child vertices should be returned.
 */
mxGraph.prototype.getChildEdges = function(parent)
{
\treturn this.getChildCells(parent, false, true);
};

/**
 * Function: getChildCells
 * 
 * Returns the visible child vertices or edges in the given parent. If
 * vertices and edges is false, then all children are returned.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be returned.
 * vertices - Optional boolean that specifies if child vertices should
 * be returned. Default is false.
 * edges - Optional boolean that specifies if child edges should
 * be returned. Default is false.
 */
mxGraph.prototype.getChildCells = function(parent, vertices, edges)
{
\tparent = (parent != null) ? parent : this.getDefaultParent();
\tvertices = (vertices != null) ? vertices : false;
\tedges = (edges != null) ? edges : false;

\tvar cells = this.model.getChildCells(parent, vertices, edges);
\tvar result = [];

\t// Filters out the non-visible child cells
\tfor (var i = 0; i < cells.length; i++)
\t{
\t\tif (this.isCellVisible(cells[i]))
\t\t{
\t\t\tresult.push(cells[i]);
\t\t}
\t}

\treturn result;
};
\t
/**
 * Function: getConnections
 * 
 * Returns all visible edges connected to the given cell without loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose connections should be returned.
 * parent - Optional parent of the opposite end for a connection to be
 * returned.
 */
mxGraph.prototype.getConnections = function(cell, parent)
{
\treturn this.getEdges(cell, parent, true, true, false);
};
\t
/**
 * Function: getIncomingEdges
 * 
 * Returns the visible incoming edges for the given cell. If the optional
 * parent argument is specified, then only child edges of the given parent
 * are returned.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose incoming edges should be returned.
 * parent - Optional parent of the opposite end for an edge to be
 * returned.
 */
mxGraph.prototype.getIncomingEdges = function(cell, parent)
{
\treturn this.getEdges(cell, parent, true, false, false);
};
\t
/**
 * Function: getOutgoingEdges
 * 
 * Returns the visible outgoing edges for the given cell. If the optional
 * parent argument is specified, then only child edges of the given parent
 * are returned.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose outgoing edges should be returned.
 * parent - Optional parent of the opposite end for an edge to be
 * returned.
 */
mxGraph.prototype.getOutgoingEdges = function(cell, parent)
{
\treturn this.getEdges(cell, parent, false, true, false);
};
\t
/**
 * Function: getEdges
 * 
 * Returns the incoming and/or outgoing edges for the given cell.
 * If the optional parent argument is specified, then only edges are returned
 * where the opposite is in the given parent cell. If at least one of incoming
 * or outgoing is true, then loops are ignored, if both are false, then all
 * edges connected to the given cell are returned including loops.
 * 
 * Parameters:
 * 
 * cell - <mxCell> whose edges should be returned.
 * parent - Optional parent of the opposite end for an edge to be
 * returned.
 * incoming - Optional boolean that specifies if incoming edges should
 * be included in the result. Default is true.
 * outgoing - Optional boolean that specifies if outgoing edges should
 * be included in the result. Default is true.
 * includeLoops - Optional boolean that specifies if loops should be
 * included in the result. Default is true.
 * recurse - Optional boolean the specifies if the parent specified only 
 * need be an ancestral parent, true, or the direct parent, false.
 * Default is false
 */
mxGraph.prototype.getEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse)
{
\tincoming = (incoming != null) ? incoming : true;
\toutgoing = (outgoing != null) ? outgoing : true;
\tincludeLoops = (includeLoops != null) ? includeLoops : true;
\trecurse = (recurse != null) ? recurse : false;
\t
\tvar edges = [];
\tvar isCollapsed = this.isCellCollapsed(cell);
\tvar childCount = this.model.getChildCount(cell);

\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = this.model.getChildAt(cell, i);

\t\tif (isCollapsed || !this.isCellVisible(child))
\t\t{
\t\t\tedges = edges.concat(this.model.getEdges(child, incoming, outgoing));
\t\t}
\t}

\tedges = edges.concat(this.model.getEdges(cell, incoming, outgoing));
\tvar result = [];
\t
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar state = this.view.getState(edges[i]);
\t\t
\t\tvar source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
\t\tvar target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);

\t\tif ((includeLoops && source == target) || ((source != target) && ((incoming &&
\t\t\ttarget == cell && (parent == null || this.isValidAncestor(source, parent, recurse))) ||
\t\t\t(outgoing && source == cell && (parent == null ||
\t\t\t\t\tthis.isValidAncestor(target, parent, recurse))))))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\treturn result;
};

/**
 * Function: isValidAncestor
 * 
 * Returns whether or not the specified parent is a valid
 * ancestor of the specified cell, either direct or indirectly
 * based on whether ancestor recursion is enabled.
 * 
 * Parameters:
 * 
 * cell - <mxCell> the possible child cell
 * parent - <mxCell> the possible parent cell
 * recurse - boolean whether or not to recurse the child ancestors
 */
mxGraph.prototype.isValidAncestor = function(cell, parent, recurse)
{
\treturn (recurse ? this.model.isAncestor(parent, cell) : this.model
\t\t\t.getParent(cell) == parent);
};

/**
 * Function: getOpposites
 * 
 * Returns all distinct visible opposite cells for the specified terminal
 * on the given edges.
 * 
 * Parameters:
 * 
 * edges - Array of <mxCells> that contains the edges whose opposite
 * terminals should be returned.
 * terminal - Terminal that specifies the end whose opposite should be
 * returned.
 * sources - Optional boolean that specifies if source terminals should be
 * included in the result. Default is true.
 * targets - Optional boolean that specifies if targer terminals should be
 * included in the result. Default is true.
 */
mxGraph.prototype.getOpposites = function(edges, terminal, sources, targets)
{
\tsources = (sources != null) ? sources : true;
\ttargets = (targets != null) ? targets : true;
\t
\tvar terminals = [];
\t
\t// Fast lookup to avoid duplicates in terminals array
\tvar dict = new mxDictionary();
\t
\tif (edges != null)
\t{
\t\tfor (var i = 0; i < edges.length; i++)
\t\t{
\t\t\tvar state = this.view.getState(edges[i]);
\t\t\t
\t\t\tvar source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
\t\t\tvar target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
\t\t\t
\t\t\t// Checks if the terminal is the source of the edge and if the
\t\t\t// target should be stored in the result
\t\t\tif (source == terminal && target != null && target != terminal && targets)
\t\t\t{
\t\t\t\tif (!dict.get(target))
\t\t\t\t{
\t\t\t\t\tdict.put(target, true);
\t\t\t\t\tterminals.push(target);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Checks if the terminal is the taget of the edge and if the
\t\t\t// source should be stored in the result
\t\t\telse if (target == terminal && source != null && source != terminal && sources)
\t\t\t{
\t\t\t\tif (!dict.get(source))
\t\t\t\t{
\t\t\t\t\tdict.put(source, true);
\t\t\t\t\tterminals.push(source);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn terminals;
};

/**
 * Function: getEdgesBetween
 * 
 * Returns the edges between the given source and target. This takes into
 * account collapsed and invisible cells and returns the connected edges
 * as displayed on the screen.
 * 
 * Parameters:
 * 
 * source -
 * target -
 * directed -
 */
mxGraph.prototype.getEdgesBetween = function(source, target, directed)
{
\tdirected = (directed != null) ? directed : false;
\tvar edges = this.getEdges(source);
\tvar result = [];

\t// Checks if the edge is connected to the correct
\t// cell and returns the first match
\tfor (var i = 0; i < edges.length; i++)
\t{
\t\tvar state = this.view.getState(edges[i]);
\t\t
\t\tvar src = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
\t\tvar trg = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);

\t\tif ((src == source && trg == target) || (!directed && src == target && trg == source))
\t\t{
\t\t\tresult.push(edges[i]);
\t\t}
\t}

\treturn result;
};

/**
 * Function: getPointForEvent
 * 
 * Returns an <mxPoint> representing the given event in the unscaled,
 * non-translated coordinate space of <container> and applies the grid.
 * 
 * Parameters:
 * 
 * evt - Mousevent that contains the mouse pointer location.
 * addOffset - Optional boolean that specifies if the position should be
 * offset by half of the <gridSize>. Default is true.
 */
 mxGraph.prototype.getPointForEvent = function(evt, addOffset)
 {
\tvar p = mxUtils.convertPoint(this.container,
\t\tmxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t
\tvar s = this.view.scale;
\tvar tr = this.view.translate;
\tvar off = (addOffset != false) ? this.gridSize / 2 : 0;
\t
\tp.x = this.snap(p.x / s - tr.x - off);
\tp.y = this.snap(p.y / s - tr.y - off);
\t
\treturn p;
};

/**
 * Function: getCells
 * 
 * Returns the child vertices and edges of the given parent that are contained
 * in the given rectangle. The result is added to the optional result array,
 * which is returned. If no result array is specified then a new array is
 * created and returned.
 * 
 * Parameters:
 * 
 * x - X-coordinate of the rectangle.
 * y - Y-coordinate of the rectangle.
 * width - Width of the rectangle.
 * height - Height of the rectangle.
 * parent - <mxCell> that should be used as the root of the recursion.
 * Default is current root of the view or the root of the model.
 * result - Optional array to store the result in.
 * intersection - Optional <mxRectangle> to check vertices for intersection.
 * ignoreFn - Optional function to check if a cell state is ignored.
 * includeDescendants - Optional boolean flag to add descendants to the result.
 * Default is false.
 */
mxGraph.prototype.getCells = function(x, y, width, height, parent, result, intersection, ignoreFn, includeDescendants)
{
\tresult = (result != null) ? result : [];
\t
\tif (width > 0 || height > 0 || intersection != null)
\t{
\t\tvar model = this.getModel();
\t\tvar right = x + width;
\t\tvar bottom = y + height;

\t\tif (parent == null)
\t\t{
\t\t\tparent = this.getCurrentRoot();
\t\t\t
\t\t\tif (parent == null)
\t\t\t{
\t\t\t\tparent = model.getRoot();
\t\t\t}
\t\t}
\t\t
\t\tif (parent != null)
\t\t{
\t\t\tvar childCount = model.getChildCount(parent);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tvar cell = model.getChildAt(parent, i);
\t\t\t\tvar state = this.view.getState(cell);
\t\t\t\t
\t\t\t\tif (state != null && this.isCellVisible(cell) &&
\t\t\t\t\t(ignoreFn == null || !ignoreFn(state)))
\t\t\t\t{
\t\t\t\t\tvar deg = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0;
\t\t\t\t\tvar box = state;
\t\t\t\t\t
\t\t\t\t\tif (deg != 0)
\t\t\t\t\t{
\t\t\t\t\t\tbox = mxUtils.getBoundingBox(box, deg);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tvar hit = (intersection != null && model.isVertex(cell) && mxUtils.intersects(intersection, box)) ||
\t\t\t\t\t\t(intersection == null && (model.isEdge(cell) || model.isVertex(cell)) &&
\t\t\t\t\t\tbox.x >= x && box.y + box.height <= bottom &&
\t\t\t\t\t\tbox.y >= y && box.x + box.width <= right);
\t\t\t\t\t
\t\t\t\t\tif (hit)
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(cell);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!hit || includeDescendants)
\t\t\t\t\t{
\t\t\t\t\t\tthis.getCells(x, y, width, height, cell, result, intersection, ignoreFn, includeDescendants);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getCellsBeyond
 * 
 * Returns the children of the given parent that are contained in the
 * halfpane from the given point (x0, y0) rightwards or downwards
 * depending on rightHalfpane and bottomHalfpane.
 * 
 * Parameters:
 * 
 * x0 - X-coordinate of the origin.
 * y0 - Y-coordinate of the origin.
 * parent - Optional <mxCell> whose children should be checked. Default is
 * <defaultParent>.
 * rightHalfpane - Boolean indicating if the cells in the right halfpane
 * from the origin should be returned.
 * bottomHalfpane - Boolean indicating if the cells in the bottom halfpane
 * from the origin should be returned.
 */
mxGraph.prototype.getCellsBeyond = function(x0, y0, parent, rightHalfpane, bottomHalfpane)
{
\tvar result = [];
\t
\tif (rightHalfpane || bottomHalfpane)
\t{
\t\tif (parent == null)
\t\t{
\t\t\tparent = this.getDefaultParent();
\t\t}
\t\t
\t\tif (parent != null)
\t\t{
\t\t\tvar childCount = this.model.getChildCount(parent);
\t\t\t
\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t{
\t\t\t\tvar child = this.model.getChildAt(parent, i);
\t\t\t\tvar state = this.view.getState(child);
\t\t\t\t
\t\t\t\tif (this.isCellVisible(child) && state != null)
\t\t\t\t{
\t\t\t\t\tif ((!rightHalfpane || state.x >= x0) &&
\t\t\t\t\t\t(!bottomHalfpane || state.y >= y0))
\t\t\t\t\t{
\t\t\t\t\t\tresult.push(child);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: findTreeRoots
 * 
 * Returns all children in the given parent which do not have incoming
 * edges. If the result is empty then the with the greatest difference
 * between incoming and outgoing edges is returned.
 * 
 * Parameters:
 * 
 * parent - <mxCell> whose children should be checked.
 * isolate - Optional boolean that specifies if edges should be ignored if
 * the opposite end is not a child of the given parent cell. Default is
 * false.
 * invert - Optional boolean that specifies if outgoing or incoming edges
 * should be counted for a tree root. If false then outgoing edges will be
 * counted. Default is false.
 */
mxGraph.prototype.findTreeRoots = function(parent, isolate, invert)
{
\tisolate = (isolate != null) ? isolate : false;
\tinvert = (invert != null) ? invert : false;
\tvar roots = [];
\t
\tif (parent != null)
\t{
\t\tvar model = this.getModel();
\t\tvar childCount = model.getChildCount(parent);
\t\tvar best = null;
\t\tvar maxDiff = 0;
\t\t
\t\tfor (var i=0; i<childCount; i++)
\t\t{
\t\t\tvar cell = model.getChildAt(parent, i);
\t\t\t
\t\t\tif (this.model.isVertex(cell) && this.isCellVisible(cell))
\t\t\t{
\t\t\t\tvar conns = this.getConnections(cell, (isolate) ? parent : null);
\t\t\t\tvar fanOut = 0;
\t\t\t\tvar fanIn = 0;
\t\t\t\t
\t\t\t\tfor (var j = 0; j < conns.length; j++)
\t\t\t\t{
\t\t\t\t\tvar src = this.view.getVisibleTerminal(conns[j], true);

                    if (src == cell)
                    {
                        fanOut++;
                    }
                    else
                    {
                        fanIn++;
                    }
\t\t\t\t}
\t\t\t\t
\t\t\t\tif ((invert && fanOut == 0 && fanIn > 0) ||
\t\t\t\t\t(!invert && fanIn == 0 && fanOut > 0))
\t\t\t\t{
\t\t\t\t\troots.push(cell);
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar diff = (invert) ? fanIn - fanOut : fanOut - fanIn;
\t\t\t\t
\t\t\t\tif (diff > maxDiff)
\t\t\t\t{
\t\t\t\t\tmaxDiff = diff;
\t\t\t\t\tbest = cell;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (roots.length == 0 && best != null)
\t\t{
\t\t\troots.push(best);
\t\t}
\t}
\t
\treturn roots;
};

/**
 * Function: traverse
 * 
 * Traverses the (directed) graph invoking the given function for each
 * visited vertex and edge. The function is invoked with the current vertex
 * and the incoming edge as a parameter. This implementation makes sure
 * each vertex is only visited once. The function may return false if the
 * traversal should stop at the given vertex.
 * 
 * Example:
 * 
 * (code)
 * mxLog.show();
 * var cell = graph.getSelectionCell();
 * graph.traverse(cell, false, function(vertex, edge)
 * {
 *   mxLog.debug(graph.getLabel(vertex));
 * });
 * (end)
 * 
 * Parameters:
 * 
 * vertex - <mxCell> that represents the vertex where the traversal starts.
 * directed - Optional boolean indicating if edges should only be traversed
 * from source to target. Default is true.
 * func - Visitor function that takes the current vertex and the incoming
 * edge as arguments. The traversal stops if the function returns false.
 * edge - Optional <mxCell> that represents the incoming edge. This is
 * null for the first step of the traversal.
 * visited - Optional <mxDictionary> from cells to true for the visited cells.
 * inverse - Optional boolean to traverse in inverse direction. Default is false.
 * This is ignored if directed is false.
 */
mxGraph.prototype.traverse = function(vertex, directed, func, edge, visited, inverse)
{
\tif (func != null && vertex != null)
\t{
\t\tdirected = (directed != null) ? directed : true;
\t\tinverse = (inverse != null) ? inverse : false;
\t\tvisited = visited || new mxDictionary();
\t\t
\t\tif (!visited.get(vertex))
\t\t{
\t\t\tvisited.put(vertex, true);
\t\t\tvar result = func(vertex, edge);
\t\t\t
\t\t\tif (result == null || result)
\t\t\t{
\t\t\t\tvar edgeCount = this.model.getEdgeCount(vertex);
\t\t\t\t
\t\t\t\tif (edgeCount > 0)
\t\t\t\t{
\t\t\t\t\tfor (var i = 0; i < edgeCount; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar e = this.model.getEdgeAt(vertex, i);
\t\t\t\t\t\tvar isSource = this.model.getTerminal(e, true) == vertex;
\t\t\t\t\t\t
\t\t\t\t\t\tif (!directed || (!inverse == isSource))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar next = this.model.getTerminal(e, !isSource);
\t\t\t\t\t\t\tthis.traverse(next, directed, func, e, visited, inverse);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Group: Selection
 */

/**
 * Function: isCellSelected
 * 
 * Returns true if the given cell is selected.
 * 
 * Parameters:
 * 
 * cell - <mxCell> for which the selection state should be returned.
 */
mxGraph.prototype.isCellSelected = function(cell)
{
\treturn this.getSelectionModel().isSelected(cell);
};

/**
 * Function: isSelectionEmpty
 * 
 * Returns true if the selection is empty.
 */
mxGraph.prototype.isSelectionEmpty = function()
{
\treturn this.getSelectionModel().isEmpty();
};

/**
 * Function: clearSelection
 * 
 * Clears the selection using <mxGraphSelectionModel.clear>.
 */
mxGraph.prototype.clearSelection = function()
{
\treturn this.getSelectionModel().clear();
};

/**
 * Function: getSelectionCount
 * 
 * Returns the number of selected cells.
 */
mxGraph.prototype.getSelectionCount = function()
{
\treturn this.getSelectionModel().cells.length;
};
\t
/**
 * Function: getSelectionCell
 * 
 * Returns the first cell from the array of selected <mxCells>.
 */
mxGraph.prototype.getSelectionCell = function()
{
\treturn this.getSelectionModel().cells[0];
};

/**
 * Function: getSelectionCells
 * 
 * Returns the array of selected <mxCells>.
 */
mxGraph.prototype.getSelectionCells = function()
{
\treturn this.getSelectionModel().cells.slice();
};

/**
 * Function: setSelectionCell
 * 
 * Sets the selection cell.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be selected.
 */
mxGraph.prototype.setSelectionCell = function(cell)
{
\tthis.getSelectionModel().setCell(cell);
};

/**
 * Function: setSelectionCells
 * 
 * Sets the selection cell.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be selected.
 */
mxGraph.prototype.setSelectionCells = function(cells)
{
\tthis.getSelectionModel().setCells(cells);
};

/**
 * Function: addSelectionCell
 * 
 * Adds the given cell to the selection.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be add to the selection.
 */
mxGraph.prototype.addSelectionCell = function(cell)
{
\tthis.getSelectionModel().addCell(cell);
};

/**
 * Function: addSelectionCells
 * 
 * Adds the given cells to the selection.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be added to the selection.
 */
mxGraph.prototype.addSelectionCells = function(cells)
{
\tthis.getSelectionModel().addCells(cells);
};

/**
 * Function: removeSelectionCell
 * 
 * Removes the given cell from the selection.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be removed from the selection.
 */
mxGraph.prototype.removeSelectionCell = function(cell)
{
\tthis.getSelectionModel().removeCell(cell);
};

/**
 * Function: removeSelectionCells
 * 
 * Removes the given cells from the selection.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be removed from the selection.
 */
mxGraph.prototype.removeSelectionCells = function(cells)
{
\tthis.getSelectionModel().removeCells(cells);
};

/**
 * Function: selectRegion
 * 
 * Selects and returns the cells inside the given rectangle for the
 * specified event.
 * 
 * Parameters:
 * 
 * rect - <mxRectangle> that represents the region to be selected.
 * evt - Mouseevent that triggered the selection.
 */
mxGraph.prototype.selectRegion = function(rect, evt)
{
\tvar cells = this.getCells(rect.x, rect.y, rect.width, rect.height);
\tthis.selectCellsForEvent(cells, evt);
\t
\treturn cells;
};

/**
 * Function: selectNextCell
 * 
 * Selects the next cell.
 */
mxGraph.prototype.selectNextCell = function()
{
\tthis.selectCell(true);
};

/**
 * Function: selectPreviousCell
 * 
 * Selects the previous cell.
 */
mxGraph.prototype.selectPreviousCell = function()
{
\tthis.selectCell();
};

/**
 * Function: selectParentCell
 * 
 * Selects the parent cell.
 */
mxGraph.prototype.selectParentCell = function()
{
\tthis.selectCell(false, true);
};

/**
 * Function: selectChildCell
 * 
 * Selects the first child cell.
 */
mxGraph.prototype.selectChildCell = function()
{
\tthis.selectCell(false, false, true);
};

/**
 * Function: selectCell
 * 
 * Selects the next, parent, first child or previous cell, if all arguments
 * are false.
 * 
 * Parameters:
 * 
 * isNext - Boolean indicating if the next cell should be selected.
 * isParent - Boolean indicating if the parent cell should be selected.
 * isChild - Boolean indicating if the first child cell should be selected.
 */
mxGraph.prototype.selectCell = function(isNext, isParent, isChild)
{
\tvar sel = this.selectionModel;
\tvar cell = (sel.cells.length > 0) ? sel.cells[0] : null;
\t
\tif (sel.cells.length > 1)
\t{
\t\tsel.clear();
\t}
\t
\tvar parent = (cell != null) ?
\t\tthis.model.getParent(cell) :
\t\tthis.getDefaultParent();
\t
\tvar childCount = this.model.getChildCount(parent);
\t
\tif (cell == null && childCount > 0)
\t{
\t\tvar child = this.model.getChildAt(parent, 0);
\t\tthis.setSelectionCell(child);
\t}
\telse if ((cell == null || isParent) &&
\t\tthis.view.getState(parent) != null &&
\t\tthis.model.getGeometry(parent) != null)
\t{
\t\tif (this.getCurrentRoot() != parent)
\t\t{
\t\t\tthis.setSelectionCell(parent);
\t\t}
\t}
\telse if (cell != null && isChild)
\t{
\t\tvar tmp = this.model.getChildCount(cell);
\t\t
\t\tif (tmp > 0)
\t\t{
\t\t\tvar child = this.model.getChildAt(cell, 0);
\t\t\tthis.setSelectionCell(child);
\t\t}
\t}
\telse if (childCount > 0)
\t{
\t\tvar i = parent.getIndex(cell);
\t\t
\t\tif (isNext)
\t\t{
\t\t\ti++;
\t\t\tvar child = this.model.getChildAt(parent, i % childCount);
\t\t\tthis.setSelectionCell(child);
\t\t}
\t\telse
\t\t{
\t\t\ti--;
\t\t\tvar index =  (i < 0) ? childCount - 1 : i;
\t\t\tvar child = this.model.getChildAt(parent, index);
\t\t\tthis.setSelectionCell(child);
\t\t}
\t}
};

/**
 * Function: selectAll
 * 
 * Selects all children of the given parent cell or the children of the
 * default parent if no parent is specified. To select leaf vertices and/or
 * edges use <selectCells>.
 * 
 * Parameters:
 * 
 * parent - Optional <mxCell> whose children should be selected.
 * Default is <defaultParent>.
 * descendants - Optional boolean specifying whether all descendants should be
 * selected. Default is false.
 */
mxGraph.prototype.selectAll = function(parent, descendants)
{
\tparent = parent || this.getDefaultParent();
\t
\tvar cells = (descendants) ? this.model.filterDescendants(mxUtils.bind(this, function(cell)
\t{
\t\treturn cell != parent && this.view.getState(cell) != null;
\t}), parent) : this.model.getChildren(parent);
\t
\tif (cells != null)
\t{
\t\tthis.setSelectionCells(cells);
\t}
};

/**
 * Function: selectVertices
 * 
 * Select all vertices inside the given parent or the default parent.
 */
mxGraph.prototype.selectVertices = function(parent, selectGroups)
{
\tthis.selectCells(true, false, parent, selectGroups);
};

/**
 * Function: selectVertices
 * 
 * Select all vertices inside the given parent or the default parent.
 */
mxGraph.prototype.selectEdges = function(parent)
{
\tthis.selectCells(false, true, parent);
};

/**
 * Function: selectCells
 * 
 * Selects all vertices and/or edges depending on the given boolean
 * arguments recursively, starting at the given parent or the default
 * parent if no parent is specified. Use <selectAll> to select all cells.
 * For vertices, only cells with no children are selected.
 * 
 * Parameters:
 * 
 * vertices - Boolean indicating if vertices should be selected.
 * edges - Boolean indicating if edges should be selected.
 * parent - Optional <mxCell> that acts as the root of the recursion.
 * Default is <defaultParent>.
 * selectGroups - Optional boolean that specifies if groups should be
 * selected. Default is false.
 */
mxGraph.prototype.selectCells = function(vertices, edges, parent, selectGroups)
{
\tparent = parent || this.getDefaultParent();
\t
\tvar filter = mxUtils.bind(this, function(cell)
\t{
\t\treturn this.view.getState(cell) != null &&
\t\t\t(((selectGroups || this.model.getChildCount(cell) == 0) &&
\t\t\tthis.model.isVertex(cell) && vertices
\t\t\t&& !this.model.isEdge(this.model.getParent(cell))) ||
\t\t\t(this.model.isEdge(cell) && edges));
\t});
\t
\tvar cells = this.model.filterDescendants(filter, parent);
\t
\tif (cells != null)
\t{
\t\tthis.setSelectionCells(cells);
\t}
};

/**
 * Function: selectCellForEvent
 * 
 * Selects the given cell by either adding it to the selection or
 * replacing the selection depending on whether the given mouse event is a
 * toggle event.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be selected.
 * evt - Optional mouseevent that triggered the selection.
 */
mxGraph.prototype.selectCellForEvent = function(cell, evt)
{
\tvar isSelected = this.isCellSelected(cell);
\t
\tif (this.isToggleEvent(evt))
\t{
\t\tif (isSelected)
\t\t{
\t\t\tthis.removeSelectionCell(cell);
\t\t}
\t\telse
\t\t{
\t\t\tthis.addSelectionCell(cell);
\t\t}
\t}
\telse if (!isSelected || this.getSelectionCount() != 1)
\t{
\t\tthis.setSelectionCell(cell);
\t}
};

/**
 * Function: selectCellsForEvent
 * 
 * Selects the given cells by either adding them to the selection or
 * replacing the selection depending on whether the given mouse event is a
 * toggle event.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> to be selected.
 * evt - Optional mouseevent that triggered the selection.
 */
mxGraph.prototype.selectCellsForEvent = function(cells, evt)
{
\tif (this.isToggleEvent(evt))
\t{
\t\tthis.addSelectionCells(cells);
\t}
\telse
\t{
\t\tthis.setSelectionCells(cells);
\t}
};

/**
 * Group: Selection state
 */

/**
 * Function: createHandler
 * 
 * Creates a new handler for the given cell state. This implementation
 * returns a new <mxEdgeHandler> of the corresponding cell is an edge,
 * otherwise it returns an <mxVertexHandler>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose handler should be created.
 */
mxGraph.prototype.createHandler = function(state)
{
\tvar result = null;
\t
\tif (state != null)
\t{
\t\tif (this.model.isEdge(state.cell))
\t\t{
\t\t\tvar source = state.getVisibleTerminalState(true);
\t\t\tvar target = state.getVisibleTerminalState(false);
\t\t\tvar geo = this.getCellGeometry(state.cell);
\t\t\t
\t\t\tvar edgeStyle = this.view.getEdgeStyle(state, (geo != null) ? geo.points : null, source, target);
\t\t\tresult = this.createEdgeHandler(state, edgeStyle);
\t\t}
\t\telse
\t\t{
\t\t\tresult = this.createVertexHandler(state);
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: createVertexHandler
 * 
 * Hooks to create a new <mxVertexHandler> for the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to create the handler for.
 */
mxGraph.prototype.createVertexHandler = function(state)
{
\treturn new mxVertexHandler(state);
};

/**
 * Function: createEdgeHandler
 * 
 * Hooks to create a new <mxEdgeHandler> for the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to create the handler for.
 */
mxGraph.prototype.createEdgeHandler = function(state, edgeStyle)
{
\tvar result = null;
\t
\tif (edgeStyle == mxEdgeStyle.Loop ||
\t\tedgeStyle == mxEdgeStyle.ElbowConnector ||
\t\tedgeStyle == mxEdgeStyle.SideToSide ||
\t\tedgeStyle == mxEdgeStyle.TopToBottom)
\t{
\t\tresult = this.createElbowEdgeHandler(state);
\t}
\telse if (edgeStyle == mxEdgeStyle.SegmentConnector || 
\t\t\tedgeStyle == mxEdgeStyle.OrthConnector)
\t{
\t\tresult = this.createEdgeSegmentHandler(state);
\t}
\telse
\t{
\t\tresult = new mxEdgeHandler(state);
\t}
\t
\treturn result;
};

/**
 * Function: createEdgeSegmentHandler
 * 
 * Hooks to create a new <mxEdgeSegmentHandler> for the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to create the handler for.
 */
mxGraph.prototype.createEdgeSegmentHandler = function(state)
{
\treturn new mxEdgeSegmentHandler(state);
};

/**
 * Function: createElbowEdgeHandler
 * 
 * Hooks to create a new <mxElbowEdgeHandler> for the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> to create the handler for.
 */
mxGraph.prototype.createElbowEdgeHandler = function(state)
{
\treturn new mxElbowEdgeHandler(state);
};

/**
 * Group: Graph events
 */

/**
 * Function: addMouseListener
 * 
 * Adds a listener to the graph event dispatch loop. The listener
 * must implement the mouseDown, mouseMove and mouseUp methods
 * as shown in the <mxMouseEvent> class.
 * 
 * Parameters:
 * 
 * listener - Listener to be added to the graph event listeners.
 */
mxGraph.prototype.addMouseListener = function(listener)
{
\tif (this.mouseListeners == null)
\t{
\t\tthis.mouseListeners = [];
\t}
\t
\tthis.mouseListeners.push(listener);
};

/**
 * Function: removeMouseListener
 * 
 * Removes the specified graph listener.
 * 
 * Parameters:
 * 
 * listener - Listener to be removed from the graph event listeners.
 */
mxGraph.prototype.removeMouseListener = function(listener)
{
\tif (this.mouseListeners != null)
\t{
\t\tfor (var i = 0; i < this.mouseListeners.length; i++)
\t\t{
\t\t\tif (this.mouseListeners[i] == listener)
\t\t\t{
\t\t\t\tthis.mouseListeners.splice(i, 1);
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: updateMouseEvent
 * 
 * Sets the graphX and graphY properties if the given <mxMouseEvent> if
 * required and returned the event.
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> to be updated.
 * evtName - Name of the mouse event.
 */
mxGraph.prototype.updateMouseEvent = function(me, evtName)
{
\tif (me.graphX == null || me.graphY == null)
\t{
\t\tvar pt = mxUtils.convertPoint(this.container, me.getX(), me.getY());
\t\t
\t\tme.graphX = pt.x - this.panDx;
\t\tme.graphY = pt.y - this.panDy;
\t\t
\t\t// Searches for rectangles using method if native hit detection is disabled on shape
\t\tif (me.getCell() == null && this.isMouseDown && evtName == mxEvent.MOUSE_MOVE)
\t\t{
\t\t\tme.state = this.view.getState(this.getCellAt(pt.x, pt.y, null, null, null, function(state)
\t\t\t{
\t\t\t\treturn state.shape == null || state.shape.paintBackground != mxRectangleShape.prototype.paintBackground ||
\t\t\t\t\tmxUtils.getValue(state.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1' ||
\t\t\t\t\t(state.shape.fill != null && state.shape.fill != mxConstants.NONE);
\t\t\t}));
\t\t}
\t}
\t
\treturn me;
};

/**
 * Function: getStateForEvent
 * 
 * Returns the state for the given touch event.
 */
mxGraph.prototype.getStateForTouchEvent = function(evt)
{
\tvar x = mxEvent.getClientX(evt);
\tvar y = mxEvent.getClientY(evt);
\t
\t// Dispatches the drop event to the graph which
\t// consumes and executes the source function
\tvar pt = mxUtils.convertPoint(this.container, x, y);

\treturn this.view.getState(this.getCellAt(pt.x, pt.y));
};

/**
 * Function: isEventIgnored
 * 
 * Returns true if the event should be ignored in <fireMouseEvent>.
 */
mxGraph.prototype.isEventIgnored = function(evtName, me, sender)
{
\tvar mouseEvent = mxEvent.isMouseEvent(me.getEvent());
\tvar result = false;

\t// Drops events that are fired more than once
\tif (me.getEvent() == this.lastEvent)
\t{
\t\tresult = true;
\t}
\telse
\t{
\t\tthis.lastEvent = me.getEvent();
\t}

\t// Installs event listeners to capture the complete gesture from the event source
\t// for non-MS touch events as a workaround for all events for the same geture being
\t// fired from the event source even if that was removed from the DOM.
\tif (this.eventSource != null && evtName != mxEvent.MOUSE_MOVE)
\t{
\t\tmxEvent.removeGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
\t\tthis.mouseMoveRedirect = null;
\t\tthis.mouseUpRedirect = null;
\t\tthis.eventSource = null;
\t}
\telse if (!mxClient.IS_GC && this.eventSource != null && me.getSource() != this.eventSource)
\t{
\t\tresult = true;
\t}
\telse if (mxClient.IS_TOUCH && evtName == mxEvent.MOUSE_DOWN &&
\t\t\t!mouseEvent && !mxEvent.isPenEvent(me.getEvent()))
\t{
\t\tthis.eventSource = me.getSource();

\t\tthis.mouseMoveRedirect = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
\t\t});
\t\tthis.mouseUpRedirect = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
\t\t});
\t\t
\t\tmxEvent.addGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
\t}

\t// Factored out the workarounds for FF to make it easier to override/remove
\t// Note this method has side-effects!
\tif (this.isSyntheticEventIgnored(evtName, me, sender))
\t{
\t\tresult = true;
\t}

\t// Never fires mouseUp/-Down for double clicks
\tif (!mxEvent.isPopupTrigger(this.lastEvent) && evtName != mxEvent.MOUSE_MOVE && this.lastEvent.detail == 2)
\t{
\t\treturn true;
\t}
\t
\t// Filters out of sequence events or mixed event types during a gesture
\tif (evtName == mxEvent.MOUSE_UP && this.isMouseDown)
\t{
\t\tthis.isMouseDown = false;
\t}
\telse if (evtName == mxEvent.MOUSE_DOWN && !this.isMouseDown)
\t{
\t\tthis.isMouseDown = true;
\t\tthis.isMouseTrigger = mouseEvent;
\t}
\t// Drops mouse events that are fired during touch gestures as a workaround for Webkit
\t// and mouse events that are not in sync with the current internal button state
\telse if (!result && (((!mxClient.IS_FF || evtName != mxEvent.MOUSE_MOVE) &&
\t\tthis.isMouseDown && this.isMouseTrigger != mouseEvent) ||
\t\t(evtName == mxEvent.MOUSE_DOWN && this.isMouseDown) ||
\t\t(evtName == mxEvent.MOUSE_UP && !this.isMouseDown)))
\t{
\t\tresult = true;
\t}
\t
\tif (!result && evtName == mxEvent.MOUSE_DOWN)
\t{
\t\tthis.lastMouseX = me.getX();
\t\tthis.lastMouseY = me.getY();
\t}

\treturn result;
};

/**
 * Function: isSyntheticEventIgnored
 * 
 * Hook for ignoring synthetic mouse events after touchend in Firefox.
 */
mxGraph.prototype.isSyntheticEventIgnored = function(evtName, me, sender)
{
\tvar result = false;
\tvar mouseEvent = mxEvent.isMouseEvent(me.getEvent());
\t
\t// LATER: This does not cover all possible cases that can go wrong in FF
\tif (this.ignoreMouseEvents && mouseEvent && evtName != mxEvent.MOUSE_MOVE)
\t{
\t\tthis.ignoreMouseEvents = evtName != mxEvent.MOUSE_UP;
\t\tresult = true;
\t}
\telse if (mxClient.IS_FF && !mouseEvent && evtName == mxEvent.MOUSE_UP)
\t{
\t\tthis.ignoreMouseEvents = true;
\t}
\t
\treturn result;
};

/**
 * Function: isEventSourceIgnored
 * 
 * Returns true if the event should be ignored in <fireMouseEvent>. This
 * implementation returns true for select, option and input (if not of type
 * checkbox, radio, button, submit or file) event sources if the event is not
 * a mouse event or a left mouse button press event.
 * 
 * Parameters:
 * 
 * evtName - The name of the event.
 * me - <mxMouseEvent> that should be ignored.
 */
mxGraph.prototype.isEventSourceIgnored = function(evtName, me)
{
\tvar source = me.getSource();
\tvar name = (source.nodeName != null) ? source.nodeName.toLowerCase() : '';
\tvar candidate = !mxEvent.isMouseEvent(me.getEvent()) || mxEvent.isLeftMouseButton(me.getEvent());
\t
\treturn evtName == mxEvent.MOUSE_DOWN && candidate && (name == 'select' || name == 'option' ||
\t\t(name == 'input' && source.type != 'checkbox' && source.type != 'radio' &&
\t\tsource.type != 'button' && source.type != 'submit' && source.type != 'file'));
};

/**
 * Function: getEventState
 * 
 * Returns the <mxCellState> to be used when firing the mouse event for the
 * given state. This implementation returns the given state.
 * 
 * Parameters:
 * 
 * <mxCellState> - State whose event source should be returned.
 */
mxGraph.prototype.getEventState = function(state)
{
\treturn state;
};

/**
 * Function: fireMouseEvent
 * 
 * Dispatches the given event in the graph event dispatch loop. Possible
 * event names are <mxEvent.MOUSE_DOWN>, <mxEvent.MOUSE_MOVE> and
 * <mxEvent.MOUSE_UP>. All listeners are invoked for all events regardless
 * of the consumed state of the event.
 * 
 * Parameters:
 * 
 * evtName - String that specifies the type of event to be dispatched.
 * me - <mxMouseEvent> to be fired.
 * sender - Optional sender argument. Default is this.
 */
mxGraph.prototype.fireMouseEvent = function(evtName, me, sender)
{
\tif (this.isEventSourceIgnored(evtName, me))
\t{
\t\tif (this.tooltipHandler != null)
\t\t{
\t\t\tthis.tooltipHandler.hide();
\t\t}
\t\t
\t\treturn;
\t}
\t
\tif (sender == null)
\t{
\t\tsender = this;
\t}

\t// Updates the graph coordinates in the event
\tme = this.updateMouseEvent(me, evtName);

\t// Detects and processes double taps for touch-based devices which do not have native double click events
\t// or where detection of double click is not always possible (quirks, IE10+). Note that this can only handle
\t// double clicks on cells because the sequence of events in IE prevents detection on the background, it fires
\t// two mouse ups, one of which without a cell but no mousedown for the second click which means we cannot
\t// detect which mouseup(s) are part of the first click, ie we do not know when the first click ends.
\tif ((!this.nativeDblClickEnabled && !mxEvent.isPopupTrigger(me.getEvent())) || (this.doubleTapEnabled &&
\t\tmxClient.IS_TOUCH && (mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent()))))
\t{
\t\tvar currentTime = new Date().getTime();
\t\t
\t\t// NOTE: Second mouseDown for double click missing in quirks mode
\t\tif ((!mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_DOWN) || (mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_UP && !this.fireDoubleClick))
\t\t{
\t\t\tif (this.lastTouchEvent != null && this.lastTouchEvent != me.getEvent() &&
\t\t\t\tcurrentTime - this.lastTouchTime < this.doubleTapTimeout &&
\t\t\t\tMath.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
\t\t\t\tMath.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance &&
\t\t\t\tthis.doubleClickCounter < 2)
\t\t\t{
\t\t\t\tthis.doubleClickCounter++;
\t\t\t\tvar doubleClickFired = false;
\t\t\t\t
\t\t\t\tif (evtName == mxEvent.MOUSE_UP)
\t\t\t\t{
\t\t\t\t\tif (me.getCell() == this.lastTouchCell && this.lastTouchCell != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.lastTouchTime = 0;
\t\t\t\t\t\tvar cell = this.lastTouchCell;
\t\t\t\t\t\tthis.lastTouchCell = null;

\t\t\t\t\t\t// Fires native dblclick event via event source
\t\t\t\t\t\t// NOTE: This fires two double click events on edges in quirks mode. While
\t\t\t\t\t\t// trying to fix this, we realized that nativeDoubleClick can be disabled for
\t\t\t\t\t\t// quirks and IE10+ (or we didn't find the case mentioned above where it
\t\t\t\t\t\t// would not work), ie. all double clicks seem to be working without this.
\t\t\t\t\t\tif (mxClient.IS_QUIRKS)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tme.getSource().fireEvent('ondblclick');
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tthis.dblClick(me.getEvent(), cell);
\t\t\t\t\t\tdoubleClickFired = true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.fireDoubleClick = true;
\t\t\t\t\tthis.lastTouchTime = 0;
\t\t\t\t}

\t\t\t\t// Do not ignore mouse up in quirks in this case
\t\t\t\tif (!mxClient.IS_QUIRKS || doubleClickFired)
\t\t\t\t{
\t\t\t\t\tmxEvent.consume(me.getEvent());
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t}
\t\t\telse if (this.lastTouchEvent == null || this.lastTouchEvent != me.getEvent())
\t\t\t{
\t\t\t\tthis.lastTouchCell = me.getCell();
\t\t\t\tthis.lastTouchX = me.getX();
\t\t\t\tthis.lastTouchY = me.getY();
\t\t\t\tthis.lastTouchTime = currentTime;
\t\t\t\tthis.lastTouchEvent = me.getEvent();
\t\t\t\tthis.doubleClickCounter = 0;
\t\t\t}
\t\t}
\t\telse if ((this.isMouseDown || evtName == mxEvent.MOUSE_UP) && this.fireDoubleClick)
\t\t{
\t\t\tthis.fireDoubleClick = false;
\t\t\tvar cell = this.lastTouchCell;
\t\t\tthis.lastTouchCell = null;
\t\t\tthis.isMouseDown = false;
\t\t\t
\t\t\t// Workaround for Chrome/Safari not firing native double click events for double touch on background
\t\t\tvar valid = (cell != null) || ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
\t\t\t\t(mxClient.IS_GC || mxClient.IS_SF));
\t\t\t
\t\t\tif (valid && Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
\t\t\t\tMath.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance)
\t\t\t{
\t\t\t\tthis.dblClick(me.getEvent(), cell);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tmxEvent.consume(me.getEvent());
\t\t\t}
\t\t\t
\t\t\treturn;
\t\t}
\t}

\tif (!this.isEventIgnored(evtName, me, sender))
\t{
\t\t// Updates the event state via getEventState
\t\tme.state = this.getEventState(me.getState());
\t\tthis.fireEvent(new mxEventObject(mxEvent.FIRE_MOUSE_EVENT, 'eventName', evtName, 'event', me));
\t\t
\t\tif ((mxClient.IS_OP || mxClient.IS_SF || mxClient.IS_GC || mxClient.IS_IE11 ||
\t\t\t(mxClient.IS_IE && mxClient.IS_SVG) || me.getEvent().target != this.container))
\t\t{
\t\t\tif (evtName == mxEvent.MOUSE_MOVE && this.isMouseDown && this.autoScroll && !mxEvent.isMultiTouchEvent(me.getEvent))
\t\t\t{
\t\t\t\tthis.scrollPointToVisible(me.getGraphX(), me.getGraphY(), this.autoExtend);
\t\t\t}
\t\t\telse if (evtName == mxEvent.MOUSE_UP && this.ignoreScrollbars && this.translateToScrollPosition &&
\t\t\t\t\t(this.container.scrollLeft != 0 || this.container.scrollTop != 0))
\t\t\t{
\t\t\t\tvar s = this.view.scale;
\t\t\t\tvar tr = this.view.translate;
\t\t\t\tthis.view.setTranslate(tr.x - this.container.scrollLeft / s, tr.y - this.container.scrollTop / s);
\t\t\t\tthis.container.scrollLeft = 0;
\t\t\t\tthis.container.scrollTop = 0;
\t\t\t}
\t\t\t
\t\t\tif (this.mouseListeners != null)
\t\t\t{
\t\t\t\tvar args = [sender, me];
\t
\t\t\t\t// Does not change returnValue in Opera
\t\t\t\tif (!me.getEvent().preventDefault)
\t\t\t\t{
\t\t\t\t\tme.getEvent().returnValue = true;
\t\t\t\t}
\t\t\t\t
\t\t\t\tfor (var i = 0; i < this.mouseListeners.length; i++)
\t\t\t\t{
\t\t\t\t\tvar l = this.mouseListeners[i];
\t\t\t\t\t
\t\t\t\t\tif (evtName == mxEvent.MOUSE_DOWN)
\t\t\t\t\t{
\t\t\t\t\t\tl.mouseDown.apply(l, args);
\t\t\t\t\t}
\t\t\t\t\telse if (evtName == mxEvent.MOUSE_MOVE)
\t\t\t\t\t{
\t\t\t\t\t\tl.mouseMove.apply(l, args);
\t\t\t\t\t}
\t\t\t\t\telse if (evtName == mxEvent.MOUSE_UP)
\t\t\t\t\t{
\t\t\t\t\t\tl.mouseUp.apply(l, args);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Invokes the click handler
\t\t\tif (evtName == mxEvent.MOUSE_UP)
\t\t\t{
\t\t\t\tthis.click(me);
\t\t\t}
\t\t}
\t\t
\t\t// Detects tapAndHold events using a timer
\t\tif ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
\t\t\tevtName == mxEvent.MOUSE_DOWN && this.tapAndHoldEnabled && !this.tapAndHoldInProgress)
\t\t{
\t\t\tthis.tapAndHoldInProgress = true;
\t\t\tthis.initialTouchX = me.getGraphX();
\t\t\tthis.initialTouchY = me.getGraphY();
\t\t\t
\t\t\tvar handler = function()
\t\t\t{
\t\t\t\tif (this.tapAndHoldValid)
\t\t\t\t{
\t\t\t\t\tthis.tapAndHold(me);
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.tapAndHoldInProgress = false;
\t\t\t\tthis.tapAndHoldValid = false;
\t\t\t};
\t\t\t
\t\t\tif (this.tapAndHoldThread)
\t\t\t{
\t\t\t\twindow.clearTimeout(this.tapAndHoldThread);
\t\t\t}
\t
\t\t\tthis.tapAndHoldThread = window.setTimeout(mxUtils.bind(this, handler), this.tapAndHoldDelay);
\t\t\tthis.tapAndHoldValid = true;
\t\t}
\t\telse if (evtName == mxEvent.MOUSE_UP)
\t\t{
\t\t\tthis.tapAndHoldInProgress = false;
\t\t\tthis.tapAndHoldValid = false;
\t\t}
\t\telse if (this.tapAndHoldValid)
\t\t{
\t\t\tthis.tapAndHoldValid =
\t\t\t\tMath.abs(this.initialTouchX - me.getGraphX()) < this.tolerance &&
\t\t\t\tMath.abs(this.initialTouchY - me.getGraphY()) < this.tolerance;
\t\t}

\t\t// Stops editing for all events other than from cellEditor
\t\tif (evtName == mxEvent.MOUSE_DOWN && this.isEditing() && !this.cellEditor.isEventSource(me.getEvent()))
\t\t{
\t\t\tthis.stopEditing(!this.isInvokesStopCellEditing());
\t\t}

\t\tthis.consumeMouseEvent(evtName, me, sender);
\t}
};

/**
 * Function: consumeMouseEvent
 * 
 * Consumes the given <mxMouseEvent> if it's a touchStart event.
 */
mxGraph.prototype.consumeMouseEvent = function(evtName, me, sender)
{
\t// Workaround for duplicate click in Windows 8 with Chrome/FF/Opera with touch
\tif (evtName == mxEvent.MOUSE_DOWN && mxEvent.isTouchEvent(me.getEvent()))
\t{
\t\tme.consume(false);
\t}
};

/**
 * Function: fireGestureEvent
 * 
 * Dispatches a <mxEvent.GESTURE> event. The following example will resize the
 * cell under the mouse based on the scale property of the native touch event.
 * 
 * (code)
 * graph.addListener(mxEvent.GESTURE, function(sender, eo)
 * {
 *   var evt = eo.getProperty('event');
 *   var state = graph.view.getState(eo.getProperty('cell'));
 *   
 *   if (graph.isEnabled() && graph.isCellResizable(state.cell) && Math.abs(1 - evt.scale) > 0.2)
 *   {
 *     var scale = graph.view.scale;
 *     var tr = graph.view.translate;
 *     
 *     var w = state.width * evt.scale;
 *     var h = state.height * evt.scale;
 *     var x = state.x - (w - state.width) / 2;
 *     var y = state.y - (h - state.height) / 2;
 *     
 *     var bounds = new mxRectangle(graph.snap(x / scale) - tr.x,
 *     \t\tgraph.snap(y / scale) - tr.y, graph.snap(w / scale), graph.snap(h / scale));
 *     graph.resizeCell(state.cell, bounds);
 *     eo.consume();
 *   }
 * });
 * (end)
 * 
 * Parameters:
 * 
 * evt - Gestureend event that represents the gesture.
 * cell - Optional <mxCell> associated with the gesture.
 */
mxGraph.prototype.fireGestureEvent = function(evt, cell)
{
\t// Resets double tap event handling when gestures take place
\tthis.lastTouchTime = 0;
\tthis.fireEvent(new mxEventObject(mxEvent.GESTURE, 'event', evt, 'cell', cell));
};

/**
 * Function: destroy
 * 
 * Destroys the graph and all its resources.
 */
mxGraph.prototype.destroy = function()
{
\tif (!this.destroyed)
\t{
\t\tthis.destroyed = true;
\t\t
\t\tif (this.tooltipHandler != null)
\t\t{
\t\t\tthis.tooltipHandler.destroy();
\t\t}
\t\t
\t\tif (this.selectionCellsHandler != null)
\t\t{
\t\t\tthis.selectionCellsHandler.destroy();
\t\t}

\t\tif (this.panningHandler != null)
\t\t{
\t\t\tthis.panningHandler.destroy();
\t\t}

\t\tif (this.popupMenuHandler != null)
\t\t{
\t\t\tthis.popupMenuHandler.destroy();
\t\t}
\t\t
\t\tif (this.connectionHandler != null)
\t\t{
\t\t\tthis.connectionHandler.destroy();
\t\t}
\t\t
\t\tif (this.graphHandler != null)
\t\t{
\t\t\tthis.graphHandler.destroy();
\t\t}
\t\t
\t\tif (this.cellEditor != null)
\t\t{
\t\t\tthis.cellEditor.destroy();
\t\t}
\t\t
\t\tif (this.view != null)
\t\t{
\t\t\tthis.view.destroy();
\t\t}

\t\tif (this.model != null && this.graphModelChangeListener != null)
\t\t{
\t\t\tthis.model.removeListener(this.graphModelChangeListener);
\t\t\tthis.graphModelChangeListener = null;
\t\t}

\t\tthis.container = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellOverlay
 *
 * Extends <mxEventSource> to implement a graph overlay, represented by an icon
 * and a tooltip. Overlays can handle and fire <click> events and are added to
 * the graph using <mxGraph.addCellOverlay>, and removed using
 * <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays.
 * The <mxGraph.getCellOverlays> function returns the array of overlays for a given
 * cell in a graph. If multiple overlays exist for the same cell, then
 * <getBounds> should be overridden in at least one of the overlays.
 * 
 * Overlays appear on top of all cells in a special layer. If this is not
 * desirable, then the image must be rendered as part of the shape or label of
 * the cell instead.
 *
 * Example:
 * 
 * The following adds a new overlays for a given vertex and selects the cell
 * if the overlay is clicked.
 *
 * (code)
 * var overlay = new mxCellOverlay(img, html);
 * graph.addCellOverlay(vertex, overlay);
 * overlay.addListener(mxEvent.CLICK, function(sender, evt)
 * {
 *   var cell = evt.getProperty('cell');
 *   graph.setSelectionCell(cell);
 * });
 * (end)
 * 
 * For cell overlays to be printed use <mxPrintPreview.printOverlays>.
 *
 * Event: mxEvent.CLICK
 *
 * Fires when the user clicks on the overlay. The <code>event</code> property
 * contains the corresponding mouse event and the <code>cell</code> property
 * contains the cell. For touch devices this is fired if the element receives
 * a touchend event.
 * 
 * Constructor: mxCellOverlay
 *
 * Constructs a new overlay using the given image and tooltip.
 * 
 * Parameters:
 * 
 * image - <mxImage> that represents the icon to be displayed.
 * tooltip - Optional string that specifies the tooltip.
 * align - Optional horizontal alignment for the overlay. Possible
 * values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT>
 * (default).
 * verticalAlign - Vertical alignment for the overlay. Possible
 * values are <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>
 * (default).
 */
function mxCellOverlay(image, tooltip, align, verticalAlign, offset, cursor)
{
\tthis.image = image;
\tthis.tooltip = tooltip;
\tthis.align = (align != null) ? align : this.align;
\tthis.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign;
\tthis.offset = (offset != null) ? offset : new mxPoint();
\tthis.cursor = (cursor != null) ? cursor : 'help';
};

/**
 * Extends mxEventSource.
 */
mxCellOverlay.prototype = new mxEventSource();
mxCellOverlay.prototype.constructor = mxCellOverlay;

/**
 * Variable: image
 *
 * Holds the <mxImage> to be used as the icon.
 */
mxCellOverlay.prototype.image = null;

/**
 * Variable: tooltip
 * 
 * Holds the optional string to be used as the tooltip.
 */
mxCellOverlay.prototype.tooltip = null;

/**
 * Variable: align
 * 
 * Holds the horizontal alignment for the overlay. Default is
 * <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the
 * center of the edge.
 */
mxCellOverlay.prototype.align = mxConstants.ALIGN_RIGHT;

/**
 * Variable: verticalAlign
 * 
 * Holds the vertical alignment for the overlay. Default is
 * <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the
 * center of the edge.
 */
mxCellOverlay.prototype.verticalAlign = mxConstants.ALIGN_BOTTOM;

/**
 * Variable: offset
 * 
 * Holds the offset as an <mxPoint>. The offset will be scaled according to the
 * current scale.
 */
mxCellOverlay.prototype.offset = null;

/**
 * Variable: cursor
 * 
 * Holds the cursor for the overlay. Default is 'help'.
 */
mxCellOverlay.prototype.cursor = null;

/**
 * Variable: defaultOverlap
 * 
 * Defines the overlapping for the overlay, that is, the proportional distance
 * from the origin to the point defined by the alignment. Default is 0.5.
 */
mxCellOverlay.prototype.defaultOverlap = 0.5;

/**
 * Function: getBounds
 * 
 * Returns the bounds of the overlay for the given <mxCellState> as an
 * <mxRectangle>. This should be overridden when using multiple overlays
 * per cell so that the overlays do not overlap.
 * 
 * The following example will place the overlay along an edge (where
 * x=[-1..1] from the start to the end of the edge and y is the
 * orthogonal offset in px).
 * 
 * (code)
 * overlay.getBounds = function(state)
 * {
 *   var bounds = mxCellOverlay.prototype.getBounds.apply(this, arguments);
 *   
 *   if (state.view.graph.getModel().isEdge(state.cell))
 *   {
 *     var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true});
 *     
 *     bounds.x = pt.x - bounds.width / 2;
 *     bounds.y = pt.y - bounds.height / 2;
 *   }
 *   
 *   return bounds;
 * };
 * (end)
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the current state of the
 * associated cell.
 */
mxCellOverlay.prototype.getBounds = function(state)
{
\tvar isEdge = state.view.graph.getModel().isEdge(state.cell);
\tvar s = state.view.scale;
\tvar pt = null;

\tvar w = this.image.width;
\tvar h = this.image.height;
\t
\tif (isEdge)
\t{
\t\tvar pts = state.absolutePoints;
\t\t
\t\tif (pts.length % 2 == 1)
\t\t{
\t\t\tpt = pts[Math.floor(pts.length / 2)];
\t\t}
\t\telse
\t\t{
\t\t\tvar idx = pts.length / 2;
\t\t\tvar p0 = pts[idx-1];
\t\t\tvar p1 = pts[idx];
\t\t\tpt = new mxPoint(p0.x + (p1.x - p0.x) / 2,
\t\t\t\tp0.y + (p1.y - p0.y) / 2);
\t\t}
\t}
\telse
\t{
\t\tpt = new mxPoint();
\t\t
\t\tif (this.align == mxConstants.ALIGN_LEFT)
\t\t{
\t\t\tpt.x = state.x;
\t\t}
\t\telse if (this.align == mxConstants.ALIGN_CENTER)
\t\t{
\t\t\tpt.x = state.x + state.width / 2;
\t\t}
\t\telse
\t\t{
\t\t\tpt.x = state.x + state.width;
\t\t}
\t\t
\t\tif (this.verticalAlign == mxConstants.ALIGN_TOP)
\t\t{
\t\t\tpt.y = state.y;
\t\t}
\t\telse if (this.verticalAlign == mxConstants.ALIGN_MIDDLE)
\t\t{
\t\t\tpt.y = state.y + state.height / 2;
\t\t}
\t\telse
\t\t{
\t\t\tpt.y = state.y + state.height;
\t\t}
\t}

\treturn new mxRectangle(Math.round(pt.x - (w * this.defaultOverlap - this.offset.x) * s),
\t\tMath.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
};

/**
 * Function: toString
 * 
 * Returns the textual representation of the overlay to be used as the
 * tooltip. This implementation returns <tooltip>.
 */
mxCellOverlay.prototype.toString = function()
{
\treturn this.tooltip;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxOutline
 *
 * Implements an outline (aka overview) for a graph. Set <updateOnPan> to true
 * to enable updates while the source graph is panning.
 * 
 * Example:
 * 
 * (code)
 * var outline = new mxOutline(graph, div);
 * (end)
 * 
 * If an outline is used in an <mxWindow> in IE8 standards mode, the following
 * code makes sure that the shadow filter is not inherited and that any
 * transparent elements in the graph do not show the page background, but the
 * background of the graph container.
 * 
 * (code)
 * if (document.documentMode == 8)
 * {
 *   container.style.filter = 'progid:DXImageTransform.Microsoft.alpha(opacity=100)';
 * }
 * (end)
 * 
 * To move the graph to the top, left corner the following code can be used.
 * 
 * (code)
 * var scale = graph.view.scale;
 * var bounds = graph.getGraphBounds();
 * graph.view.setTranslate(-bounds.x / scale, -bounds.y / scale);
 * (end)
 * 
 * To toggle the suspended mode, the following can be used.
 * 
 * (code)
 * outline.suspended = !outln.suspended;
 * if (!outline.suspended)
 * {
 *   outline.update(true);
 * }
 * (end)
 * 
 * Constructor: mxOutline
 *
 * Constructs a new outline for the specified graph inside the given
 * container.
 * 
 * Parameters:
 * 
 * source - <mxGraph> to create the outline for.
 * container - DOM node that will contain the outline.
 */
function mxOutline(source, container)
{
\tthis.source = source;

\tif (container != null)
\t{
\t\tthis.init(container);
\t}
};

/**
 * Function: source
 * 
 * Reference to the source <mxGraph>.
 */
mxOutline.prototype.source = null;

/**
 * Function: outline
 * 
 * Reference to the <mxGraph> that renders the outline.
 */
mxOutline.prototype.outline = null;

/**
 * Function: graphRenderHint
 * 
 * Renderhint to be used for the outline graph. Default is faster.
 */
mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_FASTER;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxOutline.prototype.enabled = true;

/**
 * Variable: showViewport
 * 
 * Specifies a viewport rectangle should be shown. Default is true.
 */
mxOutline.prototype.showViewport = true;

/**
 * Variable: border
 * 
 * Border to be added at the bottom and right. Default is 10.
 */
mxOutline.prototype.border = 10;

/**
 * Variable: enabled
 * 
 * Specifies the size of the sizer handler. Default is 8.
 */
mxOutline.prototype.sizerSize = 8;

/**
 * Variable: labelsVisible
 * 
 * Specifies if labels should be visible in the outline. Default is false.
 */
mxOutline.prototype.labelsVisible = false;

/**
 * Variable: updateOnPan
 * 
 * Specifies if <update> should be called for <mxEvent.PAN> in the source
 * graph. Default is false.
 */
mxOutline.prototype.updateOnPan = false;

/**
 * Variable: sizerImage
 * 
 * Optional <mxImage> to be used for the sizer. Default is null.
 */
mxOutline.prototype.sizerImage = null;

/**
 * Variable: minScale
 * 
 * Minimum scale to be used. Default is 0.0001.
 */
mxOutline.prototype.minScale = 0.0001;

/**
 * Variable: suspended
 * 
 * Optional boolean flag to suspend updates. Default is false. This flag will
 * also suspend repaints of the outline. To toggle this switch, use the
 * following code.
 * 
 * (code)
 * nav.suspended = !nav.suspended;
 * 
 * if (!nav.suspended)
 * {
 *   nav.update(true);
 * }
 * (end)
 */
mxOutline.prototype.suspended = false;

/**
 * Variable: forceVmlHandles
 * 
 * Specifies if VML should be used to render the handles in this control. This
 * is true for IE8 standards mode and false for all other browsers and modes.
 * This is a workaround for rendering issues of HTML elements over elements
 * with filters in IE 8 standards mode.
 */
mxOutline.prototype.forceVmlHandles = document.documentMode == 8;

/**
 * Function: createGraph
 * 
 * Creates the <mxGraph> used in the outline.
 */
mxOutline.prototype.createGraph = function(container)
{
\tvar graph = new mxGraph(container, this.source.getModel(), this.graphRenderHint, this.source.getStylesheet());
\tgraph.foldingEnabled = false;
\tgraph.autoScroll = false;
\t
\treturn graph;
};

/**
 * Function: init
 * 
 * Initializes the outline inside the given container.
 */
mxOutline.prototype.init = function(container)
{
\tthis.outline = this.createGraph(container);
\t
\t// Do not repaint when suspended
\tvar outlineGraphModelChanged = this.outline.graphModelChanged;
\tthis.outline.graphModelChanged = mxUtils.bind(this, function(changes)
\t{
\t\tif (!this.suspended && this.outline != null)
\t\t{
\t\t\toutlineGraphModelChanged.apply(this.outline, arguments);
\t\t}
\t});

\t// Enables faster painting in SVG
\tif (mxClient.IS_SVG)
\t{
\t\tvar node = this.outline.getView().getCanvas().parentNode;
\t\tnode.setAttribute('shape-rendering', 'optimizeSpeed');
\t\tnode.setAttribute('image-rendering', 'optimizeSpeed');
\t}
\t
\t// Hides cursors and labels
\tthis.outline.labelsVisible = this.labelsVisible;
\tthis.outline.setEnabled(false);
\t
\tthis.updateHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (!this.suspended && !this.active)
\t\t{
\t\t\tthis.update();
\t\t}
\t});
\t
\t// Updates the scale of the outline after a change of the main graph
\tthis.source.getModel().addListener(mxEvent.CHANGE, this.updateHandler);
\tthis.outline.addMouseListener(this);
\t
\t// Adds listeners to keep the outline in sync with the source graph
\tvar view = this.source.getView();
\tview.addListener(mxEvent.SCALE, this.updateHandler);
\tview.addListener(mxEvent.TRANSLATE, this.updateHandler);
\tview.addListener(mxEvent.SCALE_AND_TRANSLATE, this.updateHandler);
\tview.addListener(mxEvent.DOWN, this.updateHandler);
\tview.addListener(mxEvent.UP, this.updateHandler);

\t// Updates blue rectangle on scroll
\tmxEvent.addListener(this.source.container, 'scroll', this.updateHandler);
\t
\tthis.panHandler = mxUtils.bind(this, function(sender)
\t{
\t\tif (this.updateOnPan)
\t\t{
\t\t\tthis.updateHandler.apply(this, arguments);
\t\t}
\t});
\tthis.source.addListener(mxEvent.PAN, this.panHandler);
\t
\t// Refreshes the graph in the outline after a refresh of the main graph
\tthis.refreshHandler = mxUtils.bind(this, function(sender)
\t{
\t\tthis.outline.setStylesheet(this.source.getStylesheet());
\t\tthis.outline.refresh();
\t});
\tthis.source.addListener(mxEvent.REFRESH, this.refreshHandler);

\t// Creates the blue rectangle for the viewport
\tthis.bounds = new mxRectangle(0, 0, 0, 0);
\tthis.selectionBorder = new mxRectangleShape(this.bounds, null,
\t\tmxConstants.OUTLINE_COLOR, mxConstants.OUTLINE_STROKEWIDTH);
\tthis.selectionBorder.dialect = this.outline.dialect;

\tif (this.forceVmlHandles)
\t{
\t\tthis.selectionBorder.isHtmlAllowed = function()
\t\t{
\t\t\treturn false;
\t\t};
\t}
\t
\tthis.selectionBorder.init(this.outline.getView().getOverlayPane());

\t// Handles event by catching the initial pointer start and then listening to the
\t// complete gesture on the event target. This is needed because all the events
\t// are routed via the initial element even if that element is removed from the
\t// DOM, which happens when we repaint the selection border and zoom handles.
\tvar handler = mxUtils.bind(this, function(evt)
\t{
\t\tvar t = mxEvent.getSource(evt);
\t\t
\t\tvar redirect = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.outline.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
\t\t});
\t\t
\t\tvar redirect2 = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tmxEvent.removeGestureListeners(t, null, redirect, redirect2);
\t\t\tthis.outline.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
\t\t});
\t\t
\t\tmxEvent.addGestureListeners(t, null, redirect, redirect2);
\t\tthis.outline.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
\t});
\t
\tmxEvent.addGestureListeners(this.selectionBorder.node, handler);

\t// Creates a small blue rectangle for sizing (sizer handle)
\tthis.sizer = this.createSizer();
\t
\tif (this.forceVmlHandles)
\t{
\t\tthis.sizer.isHtmlAllowed = function()
\t\t{
\t\t\treturn false;
\t\t};
\t}
\t
\tthis.sizer.init(this.outline.getView().getOverlayPane());
\t
\tif (this.enabled)
\t{
\t\tthis.sizer.node.style.cursor = 'nwse-resize';
\t}
\t
\tmxEvent.addGestureListeners(this.sizer.node, handler);

\tthis.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
\tthis.sizer.node.style.display = this.selectionBorder.node.style.display;
\tthis.selectionBorder.node.style.cursor = 'move';

\tthis.update(false);
};

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxOutline.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * value - Boolean that specifies the new enabled state.
 */
mxOutline.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: setZoomEnabled
 * 
 * Enables or disables the zoom handling by showing or hiding the respective
 * handle.
 * 
 * Parameters:
 * 
 * value - Boolean that specifies the new enabled state.
 */
mxOutline.prototype.setZoomEnabled = function(value)
{
\tthis.sizer.node.style.visibility = (value) ? 'visible' : 'hidden';
};

/**
 * Function: refresh
 * 
 * Invokes <update> and revalidate the outline. This method is deprecated.
 */
mxOutline.prototype.refresh = function()
{
\tthis.update(true);
};

/**
 * Function: createSizer
 * 
 * Creates the shape used as the sizer.
 */
mxOutline.prototype.createSizer = function()
{
\tif (this.sizerImage != null)
\t{
\t\tvar sizer = new mxImageShape(new mxRectangle(0, 0, this.sizerImage.width, this.sizerImage.height), this.sizerImage.src);
\t\tsizer.dialect = this.outline.dialect;
\t\t
\t\treturn sizer;
\t}
\telse
\t{
\t\tvar sizer = new mxRectangleShape(new mxRectangle(0, 0, this.sizerSize, this.sizerSize),
\t\t\tmxConstants.OUTLINE_HANDLE_FILLCOLOR, mxConstants.OUTLINE_HANDLE_STROKECOLOR);
\t\tsizer.dialect = this.outline.dialect;
\t
\t\treturn sizer;
\t}
};

/**
 * Function: getSourceContainerSize
 * 
 * Returns the size of the source container.
 */
mxOutline.prototype.getSourceContainerSize = function()
{
\treturn new mxRectangle(0, 0, this.source.container.scrollWidth, this.source.container.scrollHeight);
};

/**
 * Function: getOutlineOffset
 * 
 * Returns the offset for drawing the outline graph.
 */
mxOutline.prototype.getOutlineOffset = function(scale)
{
\treturn null;
};

/**
 * Function: getSourceGraphBounds
 * 
 * Returns the graph bound boxing of the source.
 */
mxOutline.prototype.getSourceGraphBounds = function()
{
\treturn this.source.getGraphBounds();
};

/**
 * Function: update
 * 
 * Updates the outline.
 */
mxOutline.prototype.update = function(revalidate)
{
\tif (this.source != null && this.source.container != null &&
\t\tthis.outline != null && this.outline.container != null)
\t{
\t\tvar sourceScale = this.source.view.scale;
\t\tvar scaledGraphBounds = this.getSourceGraphBounds();
\t\tvar unscaledGraphBounds = new mxRectangle(scaledGraphBounds.x / sourceScale + this.source.panDx,
\t\t\t\tscaledGraphBounds.y / sourceScale + this.source.panDy, scaledGraphBounds.width / sourceScale,
\t\t\t\tscaledGraphBounds.height / sourceScale);

\t\tvar unscaledFinderBounds = new mxRectangle(0, 0,
\t\t\tthis.source.container.clientWidth / sourceScale,
\t\t\tthis.source.container.clientHeight / sourceScale);
\t\t
\t\tvar union = unscaledGraphBounds.clone();
\t\tunion.add(unscaledFinderBounds);
\t
\t\t// Zooms to the scrollable area if that is bigger than the graph
\t\tvar size = this.getSourceContainerSize();
\t\tvar completeWidth = Math.max(size.width / sourceScale, union.width);
\t\tvar completeHeight = Math.max(size.height / sourceScale, union.height);
\t
\t\tvar availableWidth = Math.max(0, this.outline.container.clientWidth - this.border);
\t\tvar availableHeight = Math.max(0, this.outline.container.clientHeight - this.border);
\t\t
\t\tvar outlineScale = Math.min(availableWidth / completeWidth, availableHeight / completeHeight);
\t\tvar scale = (isNaN(outlineScale)) ? this.minScale : Math.max(this.minScale, outlineScale);

\t\tif (scale > 0)
\t\t{
\t\t\tif (this.outline.getView().scale != scale)
\t\t\t{
\t\t\t\tthis.outline.getView().scale = scale;
\t\t\t\trevalidate = true;
\t\t\t}
\t\t
\t\t\tvar navView = this.outline.getView();
\t\t\t
\t\t\tif (navView.currentRoot != this.source.getView().currentRoot)
\t\t\t{
\t\t\t\tnavView.setCurrentRoot(this.source.getView().currentRoot);
\t\t\t}

\t\t\tvar t = this.source.view.translate;
\t\t\tvar tx = t.x + this.source.panDx;
\t\t\tvar ty = t.y + this.source.panDy;
\t\t\t
\t\t\tvar off = this.getOutlineOffset(scale);
\t\t\t
\t\t\tif (off != null)
\t\t\t{
\t\t\t\ttx += off.x;
\t\t\t\tty += off.y;
\t\t\t}
\t\t\t
\t\t\tif (unscaledGraphBounds.x < 0)
\t\t\t{
\t\t\t\ttx = tx - unscaledGraphBounds.x;
\t\t\t}
\t\t\tif (unscaledGraphBounds.y < 0)
\t\t\t{
\t\t\t\tty = ty - unscaledGraphBounds.y;
\t\t\t}
\t\t\t
\t\t\tif (navView.translate.x != tx || navView.translate.y != ty)
\t\t\t{
\t\t\t\tnavView.translate.x = tx;
\t\t\t\tnavView.translate.y = ty;
\t\t\t\trevalidate = true;
\t\t\t}
\t\t
\t\t\t// Prepares local variables for computations
\t\t\tvar t2 = navView.translate;
\t\t\tscale = this.source.getView().scale;
\t\t\tvar scale2 = scale / navView.scale;
\t\t\tvar scale3 = 1.0 / navView.scale;
\t\t\tvar container = this.source.container;
\t\t\t
\t\t\t// Updates the bounds of the viewrect in the navigation
\t\t\tthis.bounds = new mxRectangle(
\t\t\t\t(t2.x - t.x - this.source.panDx) / scale3,
\t\t\t\t(t2.y - t.y - this.source.panDy) / scale3,
\t\t\t\t(container.clientWidth / scale2),
\t\t\t\t(container.clientHeight / scale2));
\t\t\t
\t\t\t// Adds the scrollbar offset to the finder
\t\t\tthis.bounds.x += this.source.container.scrollLeft * navView.scale / scale;
\t\t\tthis.bounds.y += this.source.container.scrollTop * navView.scale / scale;
\t\t\t
\t\t\tvar b = this.selectionBorder.bounds;
\t\t\t
\t\t\tif (b.x != this.bounds.x || b.y != this.bounds.y || b.width != this.bounds.width || b.height != this.bounds.height)
\t\t\t{
\t\t\t\tthis.selectionBorder.bounds = this.bounds;
\t\t\t\tthis.selectionBorder.redraw();
\t\t\t}
\t\t
\t\t\t// Updates the bounds of the zoom handle at the bottom right
\t\t\tvar b = this.sizer.bounds;
\t\t\tvar b2 = new mxRectangle(this.bounds.x + this.bounds.width - b.width / 2,
\t\t\t\t\tthis.bounds.y + this.bounds.height - b.height / 2, b.width, b.height);

\t\t\tif (b.x != b2.x || b.y != b2.y || b.width != b2.width || b.height != b2.height)
\t\t\t{
\t\t\t\tthis.sizer.bounds = b2;
\t\t\t\t
\t\t\t\t// Avoids update of visibility in redraw for VML
\t\t\t\tif (this.sizer.node.style.visibility != 'hidden')
\t\t\t\t{
\t\t\t\t\tthis.sizer.redraw();
\t\t\t\t}
\t\t\t}

\t\t\tif (revalidate)
\t\t\t{
\t\t\t\tthis.outline.view.revalidate();
\t\t\t}
\t\t}
\t}
};

/**
 * Function: mouseDown
 * 
 * Handles the event by starting a translation or zoom.
 */
mxOutline.prototype.mouseDown = function(sender, me)
{
\tif (this.enabled && this.showViewport)
\t{
\t\tvar tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.source.tolerance : 0;
\t\tvar hit = (this.source.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
\t\t\t\tnew mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
\t\tthis.zoom = me.isSource(this.sizer) || (hit != null && mxUtils.intersects(shape.bounds, hit));
\t\tthis.startX = me.getX();
\t\tthis.startY = me.getY();
\t\tthis.active = true;

\t\tif (this.source.useScrollbarsForPanning && mxUtils.hasScrollbars(this.source.container))
\t\t{
\t\t\tthis.dx0 = this.source.container.scrollLeft;
\t\t\tthis.dy0 = this.source.container.scrollTop;
\t\t}
\t\telse
\t\t{
\t\t\tthis.dx0 = 0;
\t\t\tthis.dy0 = 0;
\t\t}
\t}

\tme.consume();
};

/**
 * Function: mouseMove
 * 
 * Handles the event by previewing the viewrect in <graph> and updating the
 * rectangle that represents the viewrect in the outline.
 */
mxOutline.prototype.mouseMove = function(sender, me)
{
\tif (this.active)
\t{
\t\tthis.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
\t\tthis.sizer.node.style.display = this.selectionBorder.node.style.display; 

\t\tvar delta = this.getTranslateForEvent(me);
\t\tvar dx = delta.x;
\t\tvar dy = delta.y;
\t\tvar bounds = null;
\t\t
\t\tif (!this.zoom)
\t\t{
\t\t\t// Previews the panning on the source graph
\t\t\tvar scale = this.outline.getView().scale;
\t\t\tbounds = new mxRectangle(this.bounds.x + dx,
\t\t\t\tthis.bounds.y + dy, this.bounds.width, this.bounds.height);
\t\t\tthis.selectionBorder.bounds = bounds;
\t\t\tthis.selectionBorder.redraw();
\t\t\tdx /= scale;
\t\t\tdx *= this.source.getView().scale;
\t\t\tdy /= scale;
\t\t\tdy *= this.source.getView().scale;
\t\t\tthis.source.panGraph(-dx - this.dx0, -dy - this.dy0);
\t\t}
\t\telse
\t\t{
\t\t\t// Does *not* preview zooming on the source graph
\t\t\tvar container = this.source.container;
\t\t\tvar viewRatio = container.clientWidth / container.clientHeight;
\t\t\tdy = dx / viewRatio;
\t\t\tbounds = new mxRectangle(this.bounds.x,
\t\t\t\tthis.bounds.y,
\t\t\t\tMath.max(1, this.bounds.width + dx),
\t\t\t\tMath.max(1, this.bounds.height + dy));
\t\t\tthis.selectionBorder.bounds = bounds;
\t\t\tthis.selectionBorder.redraw();
\t\t}
\t\t
\t\t// Updates the zoom handle
\t\tvar b = this.sizer.bounds;
\t\tthis.sizer.bounds = new mxRectangle(
\t\t\tbounds.x + bounds.width - b.width / 2,
\t\t\tbounds.y + bounds.height - b.height / 2,
\t\t\tb.width, b.height);
\t\t
\t\t// Avoids update of visibility in redraw for VML
\t\tif (this.sizer.node.style.visibility != 'hidden')
\t\t{
\t\t\tthis.sizer.redraw();
\t\t}
\t\t
\t\tme.consume();
\t}
};

/**
 * Function: getTranslateForEvent
 * 
 * Gets the translate for the given mouse event. Here is an example to limit
 * the outline to stay within positive coordinates:
 * 
 * (code)
 * outline.getTranslateForEvent = function(me)
 * {
 *   var pt = new mxPoint(me.getX() - this.startX, me.getY() - this.startY);
 *   
 *   if (!this.zoom)
 *   {
 *     var tr = this.source.view.translate;
 *     pt.x = Math.max(tr.x * this.outline.view.scale, pt.x);
 *     pt.y = Math.max(tr.y * this.outline.view.scale, pt.y);
 *   }
 *   
 *   return pt;
 * };
 * (end)
 */
mxOutline.prototype.getTranslateForEvent = function(me)
{
\treturn new mxPoint(me.getX() - this.startX, me.getY() - this.startY);
};

/**
 * Function: mouseUp
 * 
 * Handles the event by applying the translation or zoom to <graph>.
 */
mxOutline.prototype.mouseUp = function(sender, me)
{
\tif (this.active)
\t{
\t\tvar delta = this.getTranslateForEvent(me);
\t\tvar dx = delta.x;
\t\tvar dy = delta.y;
\t\t
\t\tif (Math.abs(dx) > 0 || Math.abs(dy) > 0)
\t\t{
\t\t\tif (!this.zoom)
\t\t\t{
\t\t\t\t// Applies the new translation if the source
\t\t\t\t// has no scrollbars
\t\t\t\tif (!this.source.useScrollbarsForPanning ||
\t\t\t\t\t!mxUtils.hasScrollbars(this.source.container))
\t\t\t\t{
\t\t\t\t\tthis.source.panGraph(0, 0);
\t\t\t\t\tdx /= this.outline.getView().scale;
\t\t\t\t\tdy /= this.outline.getView().scale;
\t\t\t\t\tvar t = this.source.getView().translate;
\t\t\t\t\tthis.source.getView().setTranslate(t.x - dx, t.y - dy);
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\t// Applies the new zoom
\t\t\t\tvar w = this.selectionBorder.bounds.width;
\t\t\t\tvar scale = this.source.getView().scale;
\t\t\t\tthis.source.zoomTo(Math.max(this.minScale, scale - (dx * scale) / w), false);
\t\t\t}

\t\t\tthis.update();
\t\t\tme.consume();
\t\t}
\t\t\t
\t\t// Resets the state of the handler
\t\tthis.index = null;
\t\tthis.active = false;
\t}
};

/**
 * Function: destroy
 * 
 * Destroy this outline and removes all listeners from <source>.
 */
mxOutline.prototype.destroy = function()
{
\tif (this.source != null)
\t{
\t\tthis.source.removeListener(this.panHandler);
\t\tthis.source.removeListener(this.refreshHandler);
\t\tthis.source.getModel().removeListener(this.updateHandler);
\t\tthis.source.getView().removeListener(this.updateHandler);
\t\tmxEvent.removeListener(this.source.container, 'scroll', this.updateHandler);
\t\tthis.source = null;
\t}
\t
\tif (this.outline != null)
\t{
\t\tthis.outline.removeMouseListener(this);
\t\tthis.outline.destroy();
\t\tthis.outline = null;
\t}

\tif (this.selectionBorder != null)
\t{
\t\tthis.selectionBorder.destroy();
\t\tthis.selectionBorder = null;
\t}
\t
\tif (this.sizer != null)
\t{
\t\tthis.sizer.destroy();
\t\tthis.sizer = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxMultiplicity
 * 
 * Defines invalid connections along with the error messages that they produce.
 * To add or remove rules on a graph, you must add/remove instances of this
 * class to <mxGraph.multiplicities>.
 * 
 * Example:
 * 
 * (code)
 * graph.multiplicities.push(new mxMultiplicity(
 *   true, 'rectangle', null, null, 0, 2, ['circle'],
 *   'Only 2 targets allowed',
 *   'Only circle targets allowed'));
 * (end)
 * 
 * Defines a rule where each rectangle must be connected to no more than 2
 * circles and no other types of targets are allowed.
 * 
 * Constructor: mxMultiplicity
 * 
 * Instantiate class mxMultiplicity in order to describe allowed
 * connections in a graph. Not all constraints can be enforced while
 * editing, some must be checked at validation time. The <countError> and
 * <typeError> are treated as resource keys in <mxResources>.
 * 
 * Parameters:
 * 
 * source - Boolean indicating if this rule applies to the source or target
 * terminal.
 * type - Type of the source or target terminal that this rule applies to.
 * See <type> for more information.
 * attr - Optional attribute name to match the source or target terminal.
 * value - Optional attribute value to match the source or target terminal.
 * min - Minimum number of edges for this rule. Default is 1.
 * max - Maximum number of edges for this rule. n means infinite. Default
 * is n.
 * validNeighbors - Array of types of the opposite terminal for which this
 * rule applies.
 * countError - Error to be displayed for invalid number of edges.
 * typeError - Error to be displayed for invalid opposite terminals.
 * validNeighborsAllowed - Optional boolean indicating if the array of
 * opposite types should be valid or invalid.
 */
function mxMultiplicity(source, type, attr, value, min, max,
\tvalidNeighbors, countError, typeError, validNeighborsAllowed)
{
\tthis.source = source;
\tthis.type = type;
\tthis.attr = attr;
\tthis.value = value;
\tthis.min = (min != null) ? min : 0;
\tthis.max = (max != null) ? max : 'n';
\tthis.validNeighbors = validNeighbors;
\tthis.countError = mxResources.get(countError) || countError;
\tthis.typeError = mxResources.get(typeError) || typeError;
\tthis.validNeighborsAllowed = (validNeighborsAllowed != null) ?
\t\tvalidNeighborsAllowed : true;
};

/**
 * Variable: type
 * 
 * Defines the type of the source or target terminal. The type is a string
 * passed to <mxUtils.isNode> together with the source or target vertex
 * value as the first argument.
 */
mxMultiplicity.prototype.type = null;

/**
 * Variable: attr
 * 
 * Optional string that specifies the attributename to be passed to
 * <mxUtils.isNode> to check if the rule applies to a cell.
 */
mxMultiplicity.prototype.attr = null;

/**
 * Variable: value
 * 
 * Optional string that specifies the value of the attribute to be passed
 * to <mxUtils.isNode> to check if the rule applies to a cell.
 */
mxMultiplicity.prototype.value = null;

/**
 * Variable: source
 * 
 * Boolean that specifies if the rule is applied to the source or target
 * terminal of an edge.
 */
mxMultiplicity.prototype.source = null;

/**
 * Variable: min
 * 
 * Defines the minimum number of connections for which this rule applies.
 * Default is 0.
 */
mxMultiplicity.prototype.min = null;

/**
 * Variable: max
 * 
 * Defines the maximum number of connections for which this rule applies.
 * A value of 'n' means unlimited times. Default is 'n'. 
 */
mxMultiplicity.prototype.max = null;

/**
 * Variable: validNeighbors
 * 
 * Holds an array of strings that specify the type of neighbor for which
 * this rule applies. The strings are used in <mxCell.is> on the opposite
 * terminal to check if the rule applies to the connection.
 */
mxMultiplicity.prototype.validNeighbors = null;

/**
 * Variable: validNeighborsAllowed
 * 
 * Boolean indicating if the list of validNeighbors are those that are allowed
 * for this rule or those that are not allowed for this rule.
 */
mxMultiplicity.prototype.validNeighborsAllowed = true;

/**
 * Variable: countError
 * 
 * Holds the localized error message to be displayed if the number of
 * connections for which the rule applies is smaller than <min> or greater
 * than <max>.
 */
mxMultiplicity.prototype.countError = null;

/**
 * Variable: typeError
 * 
 * Holds the localized error message to be displayed if the type of the
 * neighbor for a connection does not match the rule.
 */
mxMultiplicity.prototype.typeError = null;

/**
 * Function: check
 * 
 * Checks the multiplicity for the given arguments and returns the error
 * for the given connection or null if the multiplicity does not apply.
 *  
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph> instance.
 * edge - <mxCell> that represents the edge to validate.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 * sourceOut - Number of outgoing edges from the source terminal.
 * targetIn - Number of incoming edges for the target terminal.
 */
mxMultiplicity.prototype.check = function(graph, edge, source, target, sourceOut, targetIn)
{
\tvar error = '';

\tif ((this.source && this.checkTerminal(graph, source, edge)) ||
\t\t(!this.source && this.checkTerminal(graph, target, edge)))
\t{
\t\tif (this.countError != null && 
\t\t\t((this.source && (this.max == 0 || (sourceOut >= this.max))) ||
\t\t\t(!this.source && (this.max == 0 || (targetIn >= this.max)))))
\t\t{
\t\t\terror += this.countError + '\\n';
\t\t}

\t\tif (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0)
\t\t{
\t\t\tvar isValid = this.checkNeighbors(graph, edge, source, target);

\t\t\tif (!isValid)
\t\t\t{
\t\t\t\terror += this.typeError + '\\n';
\t\t\t}
\t\t}
\t}
\t
\treturn (error.length > 0) ? error : null;
};

/**
 * Function: checkNeighbors
 * 
 * Checks if there are any valid neighbours in <validNeighbors>. This is only
 * called if <validNeighbors> is a non-empty array.
 */
mxMultiplicity.prototype.checkNeighbors = function(graph, edge, source, target)
{
\tvar sourceValue = graph.model.getValue(source);
\tvar targetValue = graph.model.getValue(target);
\tvar isValid = !this.validNeighborsAllowed;
\tvar valid = this.validNeighbors;
\t
\tfor (var j = 0; j < valid.length; j++)
\t{
\t\tif (this.source &&
\t\t\tthis.checkType(graph, targetValue, valid[j]))
\t\t{
\t\t\tisValid = this.validNeighborsAllowed;
\t\t\tbreak;
\t\t}
\t\telse if (!this.source && 
\t\t\tthis.checkType(graph, sourceValue, valid[j]))
\t\t{
\t\t\tisValid = this.validNeighborsAllowed;
\t\t\tbreak;
\t\t}
\t}
\t
\treturn isValid;
};

/**
 * Function: checkTerminal
 * 
 * Checks the given terminal cell and returns true if this rule applies. The
 * given cell is the source or target of the given edge, depending on
 * <source>. This implementation uses <checkType> on the terminal's value.
 */
mxMultiplicity.prototype.checkTerminal = function(graph, terminal, edge)
{
\tvar value = graph.model.getValue(terminal);
\t
\treturn this.checkType(graph, value, this.type, this.attr, this.value);
};

/**
 * Function: checkType
 * 
 * Checks the type of the given value.
 */
mxMultiplicity.prototype.checkType = function(graph, value, type, attr, attrValue)
{
\tif (value != null)
\t{
\t\tif (!isNaN(value.nodeType)) // Checks if value is a DOM node
\t\t{
\t\t\treturn mxUtils.isNode(value, type, attr, attrValue);
\t\t}
\t\telse
\t\t{
\t\t\treturn value == type;
\t\t}
\t}
\t
\treturn false;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxLayoutManager
 * 
 * Implements a layout manager that runs a given layout after any changes to the graph:
 * 
 * Example:
 * 
 * (code)
 * var layoutMgr = new mxLayoutManager(graph);
 * layoutMgr.getLayout = function(cell, eventName)
 * {
 *   return layout;
 * };
 * (end)
 * 
 * See <getLayout> for a description of the possible eventNames.
 * 
 * Event: mxEvent.LAYOUT_CELLS
 * 
 * Fires between begin- and endUpdate after all cells have been layouted in
 * <layoutCells>. The <code>cells</code> property contains all cells that have
 * been passed to <layoutCells>.
 * 
 * Constructor: mxLayoutManager
 *
 * Constructs a new automatic layout for the given graph.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing graph. 
 */
function mxLayoutManager(graph)
{
\t// Executes the layout before the changes are dispatched
\tthis.undoHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled())
\t\t{
\t\t\tthis.beforeUndo(evt.getProperty('edit'));
\t\t}
\t});
\t
\t// Notifies the layout of a move operation inside a parent
\tthis.moveHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled())
\t\t{
\t\t\tthis.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
\t\t}
\t});
\t\t
\t// Notifies the layout of a move operation inside a parent
\tthis.resizeHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled())
\t\t{
\t\t\tthis.cellsResized(evt.getProperty('cells'), evt.getProperty('bounds'),
\t\t\t\tevt.getProperty('previous'));
\t\t}
\t});
\t
\tthis.setGraph(graph);
};

/**
 * Extends mxEventSource.
 */
mxLayoutManager.prototype = new mxEventSource();
mxLayoutManager.prototype.constructor = mxLayoutManager;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxLayoutManager.prototype.graph = null;

/**
 * Variable: bubbling
 * 
 * Specifies if the layout should bubble along
 * the cell hierarchy. Default is true.
 */
mxLayoutManager.prototype.bubbling = true;

/**
 * Variable: enabled
 * 
 * Specifies if event handling is enabled. Default is true.
 */
mxLayoutManager.prototype.enabled = true;

/**
 * Variable: undoHandler
 * 
 * Holds the function that handles the endUpdate event.
 */
mxLayoutManager.prototype.undoHandler = null;

/**
 * Variable: moveHandler
 * 
 * Holds the function that handles the move event.
 */
mxLayoutManager.prototype.moveHandler = null;

/**
 * Variable: resizeHandler
 * 
 * Holds the function that handles the resize event.
 */
mxLayoutManager.prototype.resizeHandler = null;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxLayoutManager.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxLayoutManager.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isBubbling
 * 
 * Returns true if a layout should bubble, that is, if the parent layout
 * should be executed whenever a cell layout (layout of the children of
 * a cell) has been executed. This implementation returns <bubbling>.
 */
mxLayoutManager.prototype.isBubbling = function()
{
\treturn this.bubbling;
};

/**
 * Function: setBubbling
 * 
 * Sets <bubbling>.
 */
mxLayoutManager.prototype.setBubbling = function(value)
{
\tthis.bubbling = value;
};

/**
 * Function: getGraph
 * 
 * Returns the graph that this layout operates on.
 */
mxLayoutManager.prototype.getGraph = function()
{
\treturn this.graph;
};

/**
 * Function: setGraph
 * 
 * Sets the graph that the layouts operate on.
 */
mxLayoutManager.prototype.setGraph = function(graph)
{
\tif (this.graph != null)
\t{
\t\tvar model = this.graph.getModel();\t\t
\t\tmodel.removeListener(this.undoHandler);
\t\tthis.graph.removeListener(this.moveHandler);
\t\tthis.graph.removeListener(this.resizeHandler);
\t}
\t
\tthis.graph = graph;
\t
\tif (this.graph != null)
\t{
\t\tvar model = this.graph.getModel();\t
\t\tmodel.addListener(mxEvent.BEFORE_UNDO, this.undoHandler);
\t\tthis.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler);
\t\tthis.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler);
\t}
};

/**
 * Function: hasLayout
 * 
 * Returns true if the given cell has a layout. This implementation invokes
 * <getLayout> with <mxEvent.LAYOUT_CELLS> as the eventName. Override this
 * if creating layouts in <getLayout> is expensive and return true if
 * <getLayout> will return a layout for the given cell for
 * <mxEvent.BEGIN_UPDATE> or <mxEvent.END_UPDATE>.
 */
mxLayoutManager.prototype.hasLayout = function(cell)
{
\treturn this.getLayout(cell, mxEvent.LAYOUT_CELLS);
};

/**
 * Function: getLayout
 * 
 * Returns the layout for the given cell and eventName. Possible
 * event names are <mxEvent.MOVE_CELLS> and <mxEvent.RESIZE_CELLS>
 * when cells are moved or resized and <mxEvent.BEGIN_UPDATE> or
 * <mxEvent.END_UPDATE> for the bottom up and top down phases after
 * changes to the graph model. <mxEvent.LAYOUT_CELLS> is used to
 * check if a layout exists for the given cell. This is called
 * from <hasLayout>.
 */
mxLayoutManager.prototype.getLayout = function(cell, eventName)
{
\treturn null;
};

/**
 * Function: beforeUndo
 * 
 * Called from <undoHandler>.
 *
 * Parameters:
 * 
 * cell - Array of <mxCells> that have been moved.
 * evt - Mouse event that represents the mousedown.
 */
mxLayoutManager.prototype.beforeUndo = function(undoableEdit)
{
\tthis.executeLayoutForCells(this.getCellsForChanges(undoableEdit.changes));
};

/**
 * Function: cellsMoved
 * 
 * Called from <moveHandler>.
 *
 * Parameters:
 * 
 * cell - Array of <mxCells> that have been moved.
 * evt - Mouse event that represents the mousedown.
 */
mxLayoutManager.prototype.cellsMoved = function(cells, evt)
{
\tif (cells != null && evt != null)
\t{
\t\tvar point = mxUtils.convertPoint(this.getGraph().container,
\t\t\tmxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t\tvar model = this.getGraph().getModel();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar layout = this.getLayout(model.getParent(cells[i]), mxEvent.MOVE_CELLS);

\t\t\tif (layout != null)
\t\t\t{
\t\t\t\tlayout.moveCell(cells[i], point.x, point.y);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: cellsResized
 * 
 * Called from <resizeHandler>.
 *
 * Parameters:
 * 
 * cell - Array of <mxCells> that have been resized.
 * bounds - <mxRectangle> taht represents the new bounds.
 */
mxLayoutManager.prototype.cellsResized = function(cells, bounds, prev)
{
\tif (cells != null && bounds != null)
\t{
\t\tvar model = this.getGraph().getModel();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar layout = this.getLayout(model.getParent(cells[i]), mxEvent.RESIZE_CELLS);

\t\t\tif (layout != null)
\t\t\t{
\t\t\t\tlayout.resizeCell(cells[i], bounds[i], prev[i]);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: getCellsForChanges
 * 
 * Returns the cells for which a layout should be executed.
 */
mxLayoutManager.prototype.getCellsForChanges = function(changes)
{
\tvar result = [];
\t
\tfor (var i = 0; i < changes.length; i++)
\t{
\t\tvar change = changes[i];
\t\t
\t\tif (change instanceof mxRootChange)
\t\t{
\t\t\treturn [];
\t\t}
\t\telse
\t\t{
\t\t\tresult = result.concat(this.getCellsForChange(change));
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: getCellsForChange
 * 
 * Executes all layouts which have been scheduled during the
 * changes.
 */
mxLayoutManager.prototype.getCellsForChange = function(change)
{
\tif (change instanceof mxChildChange)
\t{
\t\treturn this.addCellsWithLayout(change.child,
\t\t\tthis.addCellsWithLayout(change.previous));
\t}
\telse if (change instanceof mxTerminalChange ||
\t\tchange instanceof mxGeometryChange)
\t{
\t\treturn this.addCellsWithLayout(change.cell);
\t}
\telse if (change instanceof mxVisibleChange ||
\t\tchange instanceof mxStyleChange)
\t{
\t\treturn this.addCellsWithLayout(change.cell);
\t}
\t
\treturn [];
};

/**
 * Function: addCellsWithLayout
 * 
 * Adds all ancestors of the given cell that have a layout.
 */
mxLayoutManager.prototype.addCellsWithLayout = function(cell, result)
{
\treturn this.addDescendantsWithLayout(cell,
\t\tthis.addAncestorsWithLayout(cell, result));
};

/**
 * Function: addAncestorsWithLayout
 * 
 * Adds all ancestors of the given cell that have a layout.
 */
mxLayoutManager.prototype.addAncestorsWithLayout = function(cell, result)
{
\tresult = (result != null) ? result : [];
\t
\tif (cell != null)
\t{
\t\tvar layout = this.hasLayout(cell);
\t\t
\t\tif (layout != null)
\t\t{
\t\t\tresult.push(cell);
\t\t}
\t\t
\t\tif (this.isBubbling())
\t\t{
\t\t\tvar model = this.getGraph().getModel();
\t\t\tthis.addAncestorsWithLayout(
\t\t\t\tmodel.getParent(cell), result);
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: addDescendantsWithLayout
 * 
 * Adds all descendants of the given cell that have a layout.
 */
mxLayoutManager.prototype.addDescendantsWithLayout = function(cell, result)
{
\tresult = (result != null) ? result : [];
\t
\tif (cell != null && this.hasLayout(cell))
\t{
\t\tvar model = this.getGraph().getModel();
\t\t
\t\tfor (var i = 0; i < model.getChildCount(cell); i++)
\t\t{
\t\t\tvar child = model.getChildAt(cell, i);
\t\t\t
\t\t\tif (this.hasLayout(child))
\t\t\t{
\t\t\t\tresult.push(child);
\t\t\t\tthis.addDescendantsWithLayout(child, result);
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: executeLayoutForCells
 * 
 * Executes all layouts for the given cells in two phases: In the first phase
 * layouts for child cells are executed before layouts for parent cells with
 * <mxEvent.BEGIN_UPDATE>, in the second phase layouts for parent cells are
 * executed before layouts for child cells with <mxEvent.END_UPDATE>.
 */
mxLayoutManager.prototype.executeLayoutForCells = function(cells)
{
\tvar sorted = mxUtils.sortCells(cells, false);
\tthis.layoutCells(sorted, true);
\tthis.layoutCells(sorted.reverse(), false);
};

/**
 * Function: layoutCells
 * 
 * Executes all layouts which have been scheduled during the changes.
 */
mxLayoutManager.prototype.layoutCells = function(cells, bubble)
{
\tif (cells.length > 0)
\t{
\t\t// Invokes the layouts while removing duplicates
\t\tvar model = this.getGraph().getModel();
\t\t
\t\tmodel.beginUpdate();
\t\ttry 
\t\t{
\t\t\tvar last = null;
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (cells[i] != model.getRoot() && cells[i] != last)
\t\t\t\t{
\t\t\t\t\tthis.executeLayout(cells[i], bubble);
\t\t\t\t\tlast = cells[i];
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells));
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t}
};

/**
 * Function: executeLayout
 * 
 * Executes the given layout on the given parent.
 */
mxLayoutManager.prototype.executeLayout = function(cell, bubble)
{
\tvar layout = this.getLayout(cell, (bubble) ?
\t\tmxEvent.BEGIN_UPDATE : mxEvent.END_UPDATE);

\tif (layout != null)
\t{
\t\tlayout.execute(cell);
\t}
};

/**
 * Function: destroy
 * 
 * Removes all handlers from the <graph> and deletes the reference to it.
 */
mxLayoutManager.prototype.destroy = function()
{
\tthis.setGraph(null);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSwimlaneManager
 * 
 * Manager for swimlanes and nested swimlanes that sets the size of newly added
 * swimlanes to that of their siblings, and propagates changes to the size of a
 * swimlane to its siblings, if <siblings> is true, and its ancestors, if
 * <bubbling> is true.
 * 
 * Constructor: mxSwimlaneManager
 *
 * Constructs a new swimlane manager for the given graph.
 *
 * Arguments:
 * 
 * graph - Reference to the enclosing graph. 
 */
function mxSwimlaneManager(graph, horizontal, addEnabled, resizeEnabled)
{
\tthis.horizontal = (horizontal != null) ? horizontal : true;
\tthis.addEnabled = (addEnabled != null) ? addEnabled : true;
\tthis.resizeEnabled = (resizeEnabled != null) ? resizeEnabled : true;

\tthis.addHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled() && this.isAddEnabled())
\t\t{
\t\t\tthis.cellsAdded(evt.getProperty('cells'));
\t\t}
\t});
\t
\tthis.resizeHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled() && this.isResizeEnabled())
\t\t{
\t\t\tthis.cellsResized(evt.getProperty('cells'));
\t\t}
\t});
\t
\tthis.setGraph(graph);
};

/**
 * Extends mxEventSource.
 */
mxSwimlaneManager.prototype = new mxEventSource();
mxSwimlaneManager.prototype.constructor = mxSwimlaneManager;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxSwimlaneManager.prototype.graph = null;

/**
 * Variable: enabled
 * 
 * Specifies if event handling is enabled. Default is true.
 */
mxSwimlaneManager.prototype.enabled = true;

/**
 * Variable: horizontal
 * 
 * Specifies the orientation of the swimlanes. Default is true.
 */
mxSwimlaneManager.prototype.horizontal = true;

/**
 * Variable: addEnabled
 * 
 * Specifies if newly added cells should be resized to match the size of their
 * existing siblings. Default is true.
 */
mxSwimlaneManager.prototype.addEnabled = true;

/**
 * Variable: resizeEnabled
 * 
 * Specifies if resizing of swimlanes should be handled. Default is true.
 */
mxSwimlaneManager.prototype.resizeEnabled = true;

/**
 * Variable: moveHandler
 * 
 * Holds the function that handles the move event.
 */
mxSwimlaneManager.prototype.addHandler = null;

/**
 * Variable: moveHandler
 * 
 * Holds the function that handles the move event.
 */
mxSwimlaneManager.prototype.resizeHandler = null;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxSwimlaneManager.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxSwimlaneManager.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: isHorizontal
 * 
 * Returns <horizontal>.
 */
mxSwimlaneManager.prototype.isHorizontal = function()
{
\treturn this.horizontal;
};

/**
 * Function: setHorizontal
 * 
 * Sets <horizontal>.
 */
mxSwimlaneManager.prototype.setHorizontal = function(value)
{
\tthis.horizontal = value;
};

/**
 * Function: isAddEnabled
 * 
 * Returns <addEnabled>.
 */
mxSwimlaneManager.prototype.isAddEnabled = function()
{
\treturn this.addEnabled;
};

/**
 * Function: setAddEnabled
 * 
 * Sets <addEnabled>.
 */
mxSwimlaneManager.prototype.setAddEnabled = function(value)
{
\tthis.addEnabled = value;
};

/**
 * Function: isResizeEnabled
 * 
 * Returns <resizeEnabled>.
 */
mxSwimlaneManager.prototype.isResizeEnabled = function()
{
\treturn this.resizeEnabled;
};

/**
 * Function: setResizeEnabled
 * 
 * Sets <resizeEnabled>.
 */
mxSwimlaneManager.prototype.setResizeEnabled = function(value)
{
\tthis.resizeEnabled = value;
};

/**
 * Function: getGraph
 * 
 * Returns the graph that this manager operates on.
 */
mxSwimlaneManager.prototype.getGraph = function()
{
\treturn this.graph;
};

/**
 * Function: setGraph
 * 
 * Sets the graph that the manager operates on.
 */
mxSwimlaneManager.prototype.setGraph = function(graph)
{
\tif (this.graph != null)
\t{
\t\tthis.graph.removeListener(this.addHandler);
\t\tthis.graph.removeListener(this.resizeHandler);
\t}
\t
\tthis.graph = graph;
\t
\tif (this.graph != null)
\t{
\t\tthis.graph.addListener(mxEvent.ADD_CELLS, this.addHandler);
\t\tthis.graph.addListener(mxEvent.CELLS_RESIZED, this.resizeHandler);
\t}
};

/**
 * Function: isSwimlaneIgnored
 * 
 * Returns true if the given swimlane should be ignored.
 */
mxSwimlaneManager.prototype.isSwimlaneIgnored = function(swimlane)
{
\treturn !this.getGraph().isSwimlane(swimlane);
};

/**
 * Function: isCellHorizontal
 * 
 * Returns true if the given cell is horizontal. If the given cell is not a
 * swimlane, then the global orientation is returned.
 */
mxSwimlaneManager.prototype.isCellHorizontal = function(cell)
{
\tif (this.graph.isSwimlane(cell))
\t{
\t\tvar style = this.graph.getCellStyle(cell);
\t\t
\t\treturn mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, 1) == 1;
\t}
\t
\treturn !this.isHorizontal();
};

/**
 * Function: cellsAdded
 * 
 * Called if any cells have been added.
 * 
 * Parameters:
 * 
 * cell - Array of <mxCells> that have been added.
 */
mxSwimlaneManager.prototype.cellsAdded = function(cells)
{
\tif (cells != null)
\t{
\t\tvar model = this.getGraph().getModel();

\t\tmodel.beginUpdate();
\t\ttry
\t\t{
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (!this.isSwimlaneIgnored(cells[i]))
\t\t\t\t{
\t\t\t\t\tthis.swimlaneAdded(cells[i]);
\t\t\t\t}
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t}
};

/**
 * Function: swimlaneAdded
 * 
 * Updates the size of the given swimlane to match that of any existing
 * siblings swimlanes.
 * 
 * Parameters:
 * 
 * swimlane - <mxCell> that represents the new swimlane.
 */
mxSwimlaneManager.prototype.swimlaneAdded = function(swimlane)
{
\tvar model = this.getGraph().getModel();
\tvar parent = model.getParent(swimlane);
\tvar childCount = model.getChildCount(parent);
\tvar geo = null;
\t
\t// Finds the first valid sibling swimlane as reference
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(parent, i);
\t\t
\t\tif (child != swimlane && !this.isSwimlaneIgnored(child))
\t\t{
\t\t\tgeo = model.getGeometry(child);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{\t
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t}
\t
\t// Applies the size of the refernece to the newly added swimlane
\tif (geo != null)
\t{
\t\tvar parentHorizontal = (parent != null) ? this.isCellHorizontal(parent) : this.horizontal;
\t\tthis.resizeSwimlane(swimlane, geo.width, geo.height, parentHorizontal);
\t}
};

/**
 * Function: cellsResized
 * 
 * Called if any cells have been resizes. Calls <swimlaneResized> for all
 * swimlanes where <isSwimlaneIgnored> returns false.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells> whose size was changed.
 */
mxSwimlaneManager.prototype.cellsResized = function(cells)
{
\tif (cells != null)
\t{
\t\tvar model = this.getGraph().getModel();
\t\t
\t\tmodel.beginUpdate();
\t\ttry
\t\t{
\t\t\t// Finds the top-level swimlanes and adds offsets
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tif (!this.isSwimlaneIgnored(cells[i]))
\t\t\t\t{
\t\t\t\t\tvar geo = model.getGeometry(cells[i]);

\t\t\t\t\tif (geo != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar size = new mxRectangle(0, 0, geo.width, geo.height);
\t\t\t\t\t\tvar top = cells[i];
\t\t\t\t\t\tvar current = top;
\t\t\t\t\t\t
\t\t\t\t\t\twhile (current != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\ttop = current;
\t\t\t\t\t\t\tcurrent = model.getParent(current);
\t\t\t\t\t\t\tvar tmp = (this.graph.isSwimlane(current)) ?
\t\t\t\t\t\t\t\t\tthis.graph.getStartSize(current) :
\t\t\t\t\t\t\t\t\tnew mxRectangle();
\t\t\t\t\t\t\tsize.width += tmp.width;
\t\t\t\t\t\t\tsize.height += tmp.height;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tvar parentHorizontal = (current != null) ? this.isCellHorizontal(current) : this.horizontal;
\t\t\t\t\t\tthis.resizeSwimlane(top, size.width, size.height, parentHorizontal);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t}
};

/**
 * Function: resizeSwimlane
 * 
 * Called from <cellsResized> for all swimlanes that are not ignored to update
 * the size of the siblings and the size of the parent swimlanes, recursively,
 * if <bubbling> is true.
 * 
 * Parameters:
 * 
 * swimlane - <mxCell> whose size has changed.
 */
mxSwimlaneManager.prototype.resizeSwimlane = function(swimlane, w, h, parentHorizontal)
{
\tvar model = this.getGraph().getModel();
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tvar horizontal = this.isCellHorizontal(swimlane);
\t\t
\t\tif (!this.isSwimlaneIgnored(swimlane))
\t\t{
\t\t\tvar geo = model.getGeometry(swimlane);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tif ((parentHorizontal && geo.height != h) || (!parentHorizontal && geo.width != w))
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t
\t\t\t\t\tif (parentHorizontal)
\t\t\t\t\t{
\t\t\t\t\t\tgeo.height = h;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tgeo.width = w;
\t\t\t\t\t}

\t\t\t\t\tmodel.setGeometry(swimlane, geo);
\t\t\t\t}
\t\t\t}
\t\t}

\t\tvar tmp = (this.graph.isSwimlane(swimlane)) ?
\t\t\t\tthis.graph.getStartSize(swimlane) :
\t\t\t\tnew mxRectangle();
\t\tw -= tmp.width;
\t\th -= tmp.height;
\t\t
\t\tvar childCount = model.getChildCount(swimlane);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tvar child = model.getChildAt(swimlane, i);
\t\t\tthis.resizeSwimlane(child, w, h, horizontal);
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
};

/**
 * Function: destroy
 * 
 * Removes all handlers from the <graph> and deletes the reference to it.
 */
mxSwimlaneManager.prototype.destroy = function()
{
\tthis.setGraph(null);
};
/**
 * Copyright (c) 2006-2017, JGraph Ltd
 * Copyright (c) 2006-2017, Gaudenz Alder
 */
/**
 * Class: mxTemporaryCellStates
 * 
 * Creates a temporary set of cell states.
 */
function mxTemporaryCellStates(view, scale, cells, isCellVisibleFn, getLinkForCellState)
{
\tscale = (scale != null) ? scale : 1;
\tthis.view = view;
\t
\t// Stores the previous state
\tthis.oldValidateCellState = view.validateCellState;
\tthis.oldBounds = view.getGraphBounds();
\tthis.oldStates = view.getStates();
\tthis.oldScale = view.getScale();
\tthis.oldDoRedrawShape = view.graph.cellRenderer.doRedrawShape;

\tvar self = this;

\t// Overrides doRedrawShape and paint shape to add links on shapes
\tif (getLinkForCellState != null)
\t{
\t\tview.graph.cellRenderer.doRedrawShape = function(state)
\t\t{
\t\t\tvar oldPaint = state.shape.paint;
\t\t\t
\t\t\tstate.shape.paint = function(c)
\t\t\t{
\t\t\t\tvar link = getLinkForCellState(state);
\t\t\t\t
\t\t\t\tif (link != null)
\t\t\t\t{
\t\t\t\t\tc.setLink(link);
\t\t\t\t}
\t\t\t\t
\t\t\t\toldPaint.apply(this, arguments);
\t\t\t\t
\t\t\t\tif (link != null)
\t\t\t\t{
\t\t\t\t\tc.setLink(null);
\t\t\t\t}
\t\t\t};
\t\t\t
\t\t\tself.oldDoRedrawShape.apply(view.graph.cellRenderer, arguments);
\t\t\tstate.shape.paint = oldPaint;
\t\t};
\t}

\t// Overrides validateCellState to ignore invisible cells
\tview.validateCellState = function(cell, resurse)
\t{
\t\tif (cell == null || isCellVisibleFn == null || isCellVisibleFn(cell))
\t\t{
\t\t\treturn self.oldValidateCellState.apply(view, arguments);
\t\t}
\t\t
\t\treturn null;
\t};
\t
\t// Creates space for new states
\tview.setStates(new mxDictionary());
\tview.setScale(scale);
\t
\tif (cells != null)
\t{
\t\tview.resetValidationState();
\t\tvar bbox = null;

\t\t// Validates the vertices and edges without adding them to
\t\t// the model so that the original cells are not modified
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar bounds = view.getBoundingBox(view.validateCellState(view.validateCell(cells[i])));
\t\t\t
\t\t\tif (bbox == null)
\t\t\t{
\t\t\t\tbbox = bounds;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tbbox.add(bounds);
\t\t\t}
\t\t}

\t\tview.setGraphBounds(bbox || new mxRectangle());
\t}
};

/**
 * Variable: view
 *
 * Holds the width of the rectangle. Default is 0.
 */
mxTemporaryCellStates.prototype.view = null;

/**
 * Variable: oldStates
 *
 * Holds the height of the rectangle. Default is 0.
 */
mxTemporaryCellStates.prototype.oldStates = null;

/**
 * Variable: oldBounds
 *
 * Holds the height of the rectangle. Default is 0.
 */
mxTemporaryCellStates.prototype.oldBounds = null;

/**
 * Variable: oldScale
 *
 * Holds the height of the rectangle. Default is 0.
 */
mxTemporaryCellStates.prototype.oldScale = null;

/**
 * Function: destroy
 * 
 * Returns the top, left corner as a new <mxPoint>.
 */
mxTemporaryCellStates.prototype.destroy = function()
{
\tthis.view.setScale(this.oldScale);
\tthis.view.setStates(this.oldStates);
\tthis.view.setGraphBounds(this.oldBounds);
\tthis.view.validateCellState = this.oldValidateCellState;
\tthis.view.graph.cellRenderer.doRedrawShape = this.oldDoRedrawShape;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 *
 * Class: mxCellStatePreview
 * 
 * Implements a live preview for moving cells.
 * 
 * Constructor: mxCellStatePreview
 * 
 * Constructs a move preview for the given graph.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxCellStatePreview(graph)
{
\tthis.deltas = new mxDictionary();
\tthis.graph = graph;
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxCellStatePreview.prototype.graph = null;

/**
 * Variable: deltas
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxCellStatePreview.prototype.deltas = null;

/**
 * Variable: count
 * 
 * Contains the number of entries in the map.
 */
mxCellStatePreview.prototype.count = 0;

/**
 * Function: isEmpty
 * 
 * Returns true if this contains no entries.
 */
mxCellStatePreview.prototype.isEmpty = function()
{
\treturn this.count == 0;
};

/**
 * Function: moveState
 */
mxCellStatePreview.prototype.moveState = function(state, dx, dy, add, includeEdges)
{
\tadd = (add != null) ? add : true;
\tincludeEdges = (includeEdges != null) ? includeEdges : true;
\t
\tvar delta = this.deltas.get(state.cell);

\tif (delta == null)
\t{
\t\t// Note: Deltas stores the point and the state since the key is a string.
\t\tdelta = {point: new mxPoint(dx, dy), state: state};
\t\tthis.deltas.put(state.cell, delta);
\t\tthis.count++;
\t}
\telse if (add)
\t{
\t\tdelta.point.x += dx;
\t\tdelta.point.y += dy;
\t}
\telse
\t{
\t\tdelta.point.x = dx;
\t\tdelta.point.y = dy;
\t}
\t
\tif (includeEdges)
\t{
\t\tthis.addEdges(state);
\t}
\t
\treturn delta.point;
};

/**
 * Function: show
 */
mxCellStatePreview.prototype.show = function(visitor)
{
\tthis.deltas.visit(mxUtils.bind(this, function(key, delta)
\t{
\t\tthis.translateState(delta.state, delta.point.x, delta.point.y);
\t}));
\t
\tthis.deltas.visit(mxUtils.bind(this, function(key, delta)
\t{
\t\tthis.revalidateState(delta.state, delta.point.x, delta.point.y, visitor);
\t}));
};

/**
 * Function: translateState
 */
mxCellStatePreview.prototype.translateState = function(state, dx, dy)
{
\tif (state != null)
\t{
\t\tvar model = this.graph.getModel();
\t\t
\t\tif (model.isVertex(state.cell))
\t\t{
\t\t\tstate.view.updateCellState(state);
\t\t\tvar geo = model.getGeometry(state.cell);
\t\t\t
\t\t\t// Moves selection cells and non-relative vertices in
\t\t\t// the first phase so that edge terminal points will
\t\t\t// be updated in the second phase
\t\t\tif ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null))
\t\t\t{
\t\t\t\tstate.x += dx;
\t\t\t\tstate.y += dy;
\t\t\t}
\t\t}
\t    
\t    var childCount = model.getChildCount(state.cell);
\t    
\t    for (var i = 0; i < childCount; i++)
\t    {
\t    \tthis.translateState(state.view.getState(model.getChildAt(state.cell, i)), dx, dy);
\t    }
\t}
};

/**
 * Function: revalidateState
 */
mxCellStatePreview.prototype.revalidateState = function(state, dx, dy, visitor)
{
\tif (state != null)
\t{
\t\tvar model = this.graph.getModel();
\t\t
\t\t// Updates the edge terminal points and restores the
\t\t// (relative) positions of any (relative) children
\t\tif (model.isEdge(state.cell))
\t\t{
\t\t\tstate.view.updateCellState(state);
\t\t}

\t\tvar geo = this.graph.getCellGeometry(state.cell);
\t\tvar pState = state.view.getState(model.getParent(state.cell));
\t\t
\t\t// Moves selection vertices which are relative
\t\tif ((dx != 0 || dy != 0) && geo != null && geo.relative &&
\t\t\tmodel.isVertex(state.cell) && (pState == null ||
\t\t\tmodel.isVertex(pState.cell) || this.deltas.get(state.cell) != null))
\t\t{
\t\t\tstate.x += dx;
\t\t\tstate.y += dy;
\t\t}
\t\t
\t\tthis.graph.cellRenderer.redraw(state);
\t
\t\t// Invokes the visitor on the given state
\t\tif (visitor != null)
\t\t{
\t\t\tvisitor(state);
\t\t}
\t\t\t\t\t\t
\t    var childCount = model.getChildCount(state.cell);
\t    
\t    for (var i = 0; i < childCount; i++)
\t    {
\t    \tthis.revalidateState(this.graph.view.getState(model.getChildAt(state.cell, i)), dx, dy, visitor);
\t    }
\t}
};

/**
 * Function: addEdges
 */
mxCellStatePreview.prototype.addEdges = function(state)
{
\tvar model = this.graph.getModel();
\tvar edgeCount = model.getEdgeCount(state.cell);

\tfor (var i = 0; i < edgeCount; i++)
\t{
\t\tvar s = state.view.getState(model.getEdgeAt(state.cell, i));

\t\tif (s != null)
\t\t{
\t\t\tthis.moveState(s, 0, 0);
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxConnectionConstraint
 * 
 * Defines an object that contains the constraints about how to connect one
 * side of an edge to its terminal.
 * 
 * Constructor: mxConnectionConstraint
 * 
 * Constructs a new connection constraint for the given point and boolean
 * arguments.
 * 
 * Parameters:
 * 
 * point - Optional <mxPoint> that specifies the fixed location of the point
 * in relative coordinates. Default is null.
 * perimeter - Optional boolean that specifies if the fixed point should be
 * projected onto the perimeter of the terminal. Default is true.
 */
function mxConnectionConstraint(point, perimeter, name, dx, dy)
{
\tthis.point = point;
\tthis.perimeter = (perimeter != null) ? perimeter : true;
\tthis.name = name;
\tthis.dx = dx? dx : 0;
\tthis.dy = dy? dy : 0;
};

/**
 * Variable: point
 * 
 * <mxPoint> that specifies the fixed location of the connection point.
 */
mxConnectionConstraint.prototype.point = null;

/**
 * Variable: perimeter
 * 
 * Boolean that specifies if the point should be projected onto the perimeter
 * of the terminal.
 */
mxConnectionConstraint.prototype.perimeter = null;

/**
 * Variable: name
 * 
 * Optional string that specifies the name of the constraint.
 */
mxConnectionConstraint.prototype.name = null;

/**
 * Variable: dx
 * 
 * Optional float that specifies the horizontal offset of the constraint.
 */
mxConnectionConstraint.prototype.dx = null;

/**
 * Variable: dy
 * 
 * Optional float that specifies the vertical offset of the constraint.
 */
mxConnectionConstraint.prototype.dy = null;

/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGraphHandler
 * 
 * Graph event handler that handles selection. Individual cells are handled
 * separately using <mxVertexHandler> or one of the edge handlers. These
 * handlers are created using <mxGraph.createHandler> in
 * <mxGraphSelectionModel.cellAdded>.
 * 
 * To avoid the container to scroll a moved cell into view, set
 * <scrollAfterMove> to false.
 * 
 * Constructor: mxGraphHandler
 * 
 * Constructs an event handler that creates handles for the
 * selection cells.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxGraphHandler(graph)
{
\tthis.graph = graph;
\tthis.graph.addMouseListener(this);
\t
\t// Repaints the handler after autoscroll
\tthis.panHandler = mxUtils.bind(this, function()
\t{
\t\tif (!this.suspended)
\t\t{
\t\t\tthis.updatePreview();
\t\t\tthis.updateHint();
\t\t}
\t});
\t
\tthis.graph.addListener(mxEvent.PAN, this.panHandler);
\t
\t// Handles escape keystrokes
\tthis.escapeHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tthis.reset();
\t});
\t
\tthis.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
\t
\t// Updates the preview box for remote changes
\tthis.refreshHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\t// Merges multiple pending calls
\t\tif (this.refreshThread)
\t\t{
\t\t\twindow.clearTimeout(this.refreshThread);
\t\t}

\t\t// Waits for the states and handlers to be updated
\t\tthis.refreshThread = window.setTimeout(mxUtils.bind(this, function()
\t\t{
\t\t\tthis.refreshThread = null;
\t\t\t
\t\t\tif (this.first != null && !this.suspended)
\t\t\t{
\t\t\t\t// Updates preview with no translate to compute bounding box
\t\t\t\tvar dx = this.currentDx;
\t\t\t\tvar dy = this.currentDy;
\t\t\t\tthis.currentDx = 0;
\t\t\t\tthis.currentDy = 0;
\t\t\t\tthis.updatePreview();
\t\t\t\tthis.bounds = this.graph.getView().getBounds(this.cells);
\t\t\t\tthis.pBounds = this.getPreviewBounds(this.cells);

\t\t\t\tif (this.pBounds == null && !this.livePreviewUsed)
\t\t\t\t{
\t\t\t\t\tthis.reset();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\t// Restores translate and updates preview
\t\t\t\t\tthis.currentDx = dx;
\t\t\t\t\tthis.currentDy = dy;
\t\t\t\t\tthis.updatePreview();
\t\t\t\t\tthis.updateHint();

\t\t\t\t\tif (this.livePreviewUsed)
\t\t\t\t\t{
\t\t\t\t\t\t// Forces update to ignore last visible state
\t\t\t\t\t\tthis.setHandlesVisibleForCells(
\t\t\t\t\t\t\tthis.graph.selectionCellsHandler.
\t\t\t\t\t\t\tgetHandledSelectionCells(), false, true);
\t\t\t\t\t\tthis.updatePreview();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}), 0);
\t});
\t
\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler);
\tthis.graph.addListener(mxEvent.REFRESH, this.refreshHandler);
\t
\tthis.keyHandler = mxUtils.bind(this, function(e)
\t{
\t\tif (this.graph.container != null && this.graph.container.style.visibility != 'hidden' &&
\t\t\tthis.first != null && !this.suspended)
\t\t{
\t\t\tvar clone = this.graph.isCloneEvent(e) &&
\t\t\t\tthis.graph.isCellsCloneable() &&
\t\t\t\tthis.isCloneEnabled();
\t\t\t
\t\t\tif (clone != this.cloning)
\t\t\t{
\t\t\t\tthis.cloning = clone;
\t\t\t\tthis.checkPreview();
\t\t\t\tthis.updatePreview();
\t\t\t}
\t\t}
\t});
\t
\tmxEvent.addListener(document, 'keydown', this.keyHandler);
\tmxEvent.addListener(document, 'keyup', this.keyHandler);
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxGraphHandler.prototype.graph = null;

/**
 * Variable: maxCells
 * 
 * Defines the maximum number of cells to paint subhandles
 * for. Default is 50 for Firefox and 20 for IE. Set this
 * to 0 if you want an unlimited number of handles to be
 * displayed. This is only recommended if the number of
 * cells in the graph is limited to a small number, eg.
 * 500.
 */
mxGraphHandler.prototype.maxCells = (mxClient.IS_IE) ? 20 : 50;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxGraphHandler.prototype.enabled = true;

/**
 * Variable: highlightEnabled
 * 
 * Specifies if drop targets under the mouse should be enabled. Default is
 * true.
 */
mxGraphHandler.prototype.highlightEnabled = true;

/**
 * Variable: cloneEnabled
 * 
 * Specifies if cloning by control-drag is enabled. Default is true.
 */
mxGraphHandler.prototype.cloneEnabled = true;

/**
 * Variable: moveEnabled
 * 
 * Specifies if moving is enabled. Default is true.
 */
mxGraphHandler.prototype.moveEnabled = true;

/**
 * Variable: guidesEnabled
 * 
 * Specifies if other cells should be used for snapping the right, center or
 * left side of the current selection. Default is false.
 */
mxGraphHandler.prototype.guidesEnabled = false;

/**
 * Variable: handlesVisible
 * 
 * Whether the handles of the selection are currently visible.
 */
mxGraphHandler.prototype.handlesVisible = true;

/**
 * Variable: guide
 * 
 * Holds the <mxGuide> instance that is used for alignment.
 */
mxGraphHandler.prototype.guide = null;

/**
 * Variable: currentDx
 * 
 * Stores the x-coordinate of the current mouse move.
 */
mxGraphHandler.prototype.currentDx = null;

/**
 * Variable: currentDy
 * 
 * Stores the y-coordinate of the current mouse move.
 */
mxGraphHandler.prototype.currentDy = null;

/**
 * Variable: updateCursor
 * 
 * Specifies if a move cursor should be shown if the mouse is over a movable
 * cell. Default is true.
 */
mxGraphHandler.prototype.updateCursor = true;

/**
 * Variable: selectEnabled
 * 
 * Specifies if selecting is enabled. Default is true.
 */
mxGraphHandler.prototype.selectEnabled = true;

/**
 * Variable: removeCellsFromParent
 * 
 * Specifies if cells may be moved out of their parents. Default is true.
 */
mxGraphHandler.prototype.removeCellsFromParent = true;

/**
 * Variable: removeEmptyParents
 * 
 * If empty parents should be removed from the model after all child cells
 * have been moved out. Default is true.
 */
mxGraphHandler.prototype.removeEmptyParents = false;

/**
 * Variable: connectOnDrop
 * 
 * Specifies if drop events are interpreted as new connections if no other
 * drop action is defined. Default is false.
 */
mxGraphHandler.prototype.connectOnDrop = false;

/**
 * Variable: scrollOnMove
 * 
 * Specifies if the view should be scrolled so that a moved cell is
 * visible. Default is true.
 */
mxGraphHandler.prototype.scrollOnMove = true;

/**
 * Variable: minimumSize
 * 
 * Specifies the minimum number of pixels for the width and height of a
 * selection border. Default is 6.
 */
mxGraphHandler.prototype.minimumSize = 6;

/**
 * Variable: previewColor
 * 
 * Specifies the color of the preview shape. Default is black.
 */
mxGraphHandler.prototype.previewColor = 'black';

/**
 * Variable: htmlPreview
 * 
 * Specifies if the graph container should be used for preview. If this is used
 * then drop target detection relies entirely on <mxGraph.getCellAt> because
 * the HTML preview does not \"let events through\". Default is false.
 */
mxGraphHandler.prototype.htmlPreview = false;

/**
 * Variable: shape
 * 
 * Reference to the <mxShape> that represents the preview.
 */
mxGraphHandler.prototype.shape = null;

/**
 * Variable: scaleGrid
 * 
 * Specifies if the grid should be scaled. Default is false.
 */
mxGraphHandler.prototype.scaleGrid = false;

/**
 * Variable: rotationEnabled
 * 
 * Specifies if the bounding box should allow for rotation. Default is true.
 */
mxGraphHandler.prototype.rotationEnabled = true;

/**
 * Variable: maxLivePreview
 * 
 * Maximum number of cells for which live preview should be used. Default is 0
 * which means no live preview.
 */
mxGraphHandler.prototype.maxLivePreview = 0;

/**
 * Variable: allowLivePreview
 * 
 * If live preview is allowed on this system. Default is true for systems with
 * SVG support.
 */
mxGraphHandler.prototype.allowLivePreview = mxClient.IS_SVG;

/**
 * Function: isEnabled
 * 
 * Returns <enabled>.
 */
mxGraphHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Sets <enabled>.
 */
mxGraphHandler.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: isCloneEnabled
 * 
 * Returns <cloneEnabled>.
 */
mxGraphHandler.prototype.isCloneEnabled = function()
{
\treturn this.cloneEnabled;
};

/**
 * Function: setCloneEnabled
 * 
 * Sets <cloneEnabled>.
 * 
 * Parameters:
 * 
 * value - Boolean that specifies the new clone enabled state.
 */
mxGraphHandler.prototype.setCloneEnabled = function(value)
{
\tthis.cloneEnabled = value;
};

/**
 * Function: isMoveEnabled
 * 
 * Returns <moveEnabled>.
 */
mxGraphHandler.prototype.isMoveEnabled = function()
{
\treturn this.moveEnabled;
};

/**
 * Function: setMoveEnabled
 * 
 * Sets <moveEnabled>.
 */
mxGraphHandler.prototype.setMoveEnabled = function(value)
{
\tthis.moveEnabled = value;
};

/**
 * Function: isSelectEnabled
 * 
 * Returns <selectEnabled>.
 */
mxGraphHandler.prototype.isSelectEnabled = function()
{
\treturn this.selectEnabled;
};

/**
 * Function: setSelectEnabled
 * 
 * Sets <selectEnabled>.
 */
mxGraphHandler.prototype.setSelectEnabled = function(value)
{
\tthis.selectEnabled = value;
};

/**
 * Function: isRemoveCellsFromParent
 * 
 * Returns <removeCellsFromParent>.
 */
mxGraphHandler.prototype.isRemoveCellsFromParent = function()
{
\treturn this.removeCellsFromParent;
};

/**
 * Function: setRemoveCellsFromParent
 * 
 * Sets <removeCellsFromParent>.
 */
mxGraphHandler.prototype.setRemoveCellsFromParent = function(value)
{
\tthis.removeCellsFromParent = value;
};

/**
 * Function: isPropagateSelectionCell
 * 
 * Returns true if the given cell and parent should propagate
 * selection state to the parent.
 */
mxGraphHandler.prototype.isPropagateSelectionCell = function(cell, immediate, me)
{
\tvar parent = this.graph.model.getParent(cell);

\tif (immediate)
\t{
\t\tvar geo = (this.graph.model.isEdge(cell)) ? null :
\t\t\tthis.graph.getCellGeometry(cell);
\t\t
\t\treturn !this.graph.isSiblingSelected(cell) &&
\t\t\t((geo != null && geo.relative) ||
\t\t\t!this.graph.isSwimlane(parent));
\t}
\telse
\t{
\t\treturn (!this.graph.isToggleEvent(me.getEvent()) ||
\t\t\t(!this.graph.isSiblingSelected(cell) &&
\t\t\t!this.graph.isCellSelected(cell) &&
\t\t\t(!this.graph.isSwimlane(parent)) ||
\t\t\tthis.graph.isCellSelected(parent))) &&
\t\t\t(this.graph.isToggleEvent(me.getEvent()) ||
\t\t\t!this.graph.isCellSelected(parent));
\t}
};

/**
 * Function: getInitialCellForEvent
 * 
 * Hook to return initial cell for the given event. This returns
 * the topmost cell that is not a swimlane or is selected.
 */
mxGraphHandler.prototype.getInitialCellForEvent = function(me)
{
\tvar state = me.getState();
\t
\tif ((!this.graph.isToggleEvent(me.getEvent()) || !mxEvent.isAltDown(me.getEvent())) &&
\t\tstate != null && !this.graph.isCellSelected(state.cell))
\t{
\t\tvar model = this.graph.model;
\t\tvar next = this.graph.view.getState(model.getParent(state.cell));

\t\twhile (next != null && !this.graph.isCellSelected(next.cell) &&
\t\t\t(model.isVertex(next.cell) || model.isEdge(next.cell)) &&
\t\t\tthis.isPropagateSelectionCell(state.cell, true, me))
\t\t{
\t\t\tstate = next;
\t\t\tnext = this.graph.view.getState(this.graph.getModel().getParent(state.cell));
\t\t}
\t}
\t
\treturn (state != null) ? state.cell : null;
};

/**
 * Function: isDelayedSelection
 * 
 * Returns true if the cell or one of its ancestors is selected.
 */
mxGraphHandler.prototype.isDelayedSelection = function(cell, me)
{
\tif (!this.graph.isToggleEvent(me.getEvent()) || !mxEvent.isAltDown(me.getEvent()))
\t{
\t\twhile (cell != null)
\t\t{
\t\t\tif (this.graph.selectionCellsHandler.isHandled(cell))
\t\t\t{
\t\t\t\treturn this.graph.cellEditor.getEditingCell() != cell;
\t\t\t}
\t\t\t
\t\t\tcell = this.graph.model.getParent(cell);
\t\t}
\t}
\t
\treturn this.graph.isToggleEvent(me.getEvent()) && !mxEvent.isAltDown(me.getEvent());
};

/**
 * Function: selectDelayed
 * 
 * Implements the delayed selection for the given mouse event.
 */
mxGraphHandler.prototype.selectDelayed = function(me)
{
\tif (!this.graph.popupMenuHandler.isPopupTrigger(me))
\t{
\t\tvar cell = me.getCell();
\t\t
\t\tif (cell == null)
\t\t{
\t\t\tcell = this.cell;
\t\t}
\t\t
\t\tthis.selectCellForEvent(cell, me);
\t}
};

/**
 * Function: selectCellForEvent
 * 
 * Selects the given cell for the given <mxMouseEvent>.
 */
mxGraphHandler.prototype.selectCellForEvent = function(cell, me)
{
\tvar state = this.graph.view.getState(cell);
\t
\tif (state != null)
\t{
\t\tif (me.isSource(state.control))
\t\t{
\t\t\tthis.graph.selectCellForEvent(cell, me.getEvent());
\t\t}
\t\telse
\t\t{
\t\t\tif (!this.graph.isToggleEvent(me.getEvent()) ||
\t\t\t\t!mxEvent.isAltDown(me.getEvent()))
\t\t\t{
\t\t\t\tvar model = this.graph.getModel();
\t\t\t\tvar parent = model.getParent(cell);
\t\t\t\t
\t\t\t\twhile (this.graph.view.getState(parent) != null &&
\t\t\t\t\t(model.isVertex(parent) || model.isEdge(parent)) &&
\t\t\t\t\tthis.isPropagateSelectionCell(cell, false, me))
\t\t\t\t{
\t\t\t\t\tcell = parent;
\t\t\t\t\tparent = model.getParent(cell);
\t\t\t\t}
\t\t\t}

\t\t\tthis.graph.selectCellForEvent(cell, me.getEvent());
\t\t}
\t}
\t
\treturn cell;
};

/**
 * Function: consumeMouseEvent
 * 
 * Consumes the given mouse event. NOTE: This may be used to enable click
 * events for links in labels on iOS as follows as consuming the initial
 * touchStart disables firing the subsequent click event on the link.
 * 
 * <code>
 * mxGraphHandler.prototype.consumeMouseEvent = function(evtName, me)
 * {
 *   var source = mxEvent.getSource(me.getEvent());
 *   
 *   if (!mxEvent.isTouchEvent(me.getEvent()) || source.nodeName != 'A')
 *   {
 *     me.consume();
 *   }
 * }
 * </code>
 */
mxGraphHandler.prototype.consumeMouseEvent = function(evtName, me)
{
\tme.consume();
};

/**
 * Function: mouseDown
 * 
 * Handles the event by selecing the given cell and creating a handle for
 * it. By consuming the event all subsequent events of the gesture are
 * redirected to this handler.
 */
mxGraphHandler.prototype.mouseDown = function(sender, me)
{
\tif (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
\t\tme.getState() != null && !mxEvent.isMultiTouchEvent(me.getEvent()))
\t{
\t\tvar cell = this.getInitialCellForEvent(me);
\t\tthis.delayedSelection = this.isDelayedSelection(cell, me);
\t\tthis.cell = null;
\t\t
\t\tif (this.isSelectEnabled() && !this.delayedSelection)
\t\t{
\t\t\tthis.graph.selectCellForEvent(cell, me.getEvent());
\t\t}

\t\tif (this.isMoveEnabled())
\t\t{
\t\t\tvar model = this.graph.model;
\t\t\tvar geo = model.getGeometry(cell);

\t\t\tif (this.graph.isCellMovable(cell) && ((!model.isEdge(cell) || this.graph.getSelectionCount() > 1 ||
\t\t\t\t(geo.points != null && geo.points.length > 0) || model.getTerminal(cell, true) == null ||
\t\t\t\tmodel.getTerminal(cell, false) == null) || this.graph.allowDanglingEdges || 
\t\t\t\t(this.graph.isCloneEvent(me.getEvent()) && this.graph.isCellsCloneable())))
\t\t\t{
\t\t\t\tthis.start(cell, me.getX(), me.getY());
\t\t\t}
\t\t\telse if (this.delayedSelection)
\t\t\t{
\t\t\t\tthis.cell = cell;
\t\t\t}

\t\t\tthis.cellWasClicked = true;
\t\t\tthis.consumeMouseEvent(mxEvent.MOUSE_DOWN, me);
\t\t}
\t}
};

/**
 * Function: getGuideStates
 * 
 * Creates an array of cell states which should be used as guides.
 */
mxGraphHandler.prototype.getGuideStates = function()
{
\tvar parent = this.graph.getDefaultParent();
\tvar model = this.graph.getModel();
\t
\tvar filter = mxUtils.bind(this, function(cell)
\t{
\t\treturn this.graph.view.getState(cell) != null &&
\t\t\tmodel.isVertex(cell) &&
\t\t\tmodel.getGeometry(cell) != null &&
\t\t\t!model.getGeometry(cell).relative;
\t});
\t
\treturn this.graph.view.getCellStates(model.filterDescendants(filter, parent));
};

/**
 * Function: getCells
 * 
 * Returns the cells to be modified by this handler. This implementation
 * returns all selection cells that are movable, or the given initial cell if
 * the given cell is not selected and movable. This handles the case of moving
 * unselectable or unselected cells.
 * 
 * Parameters:
 * 
 * initialCell - <mxCell> that triggered this handler.
 */
mxGraphHandler.prototype.getCells = function(initialCell)
{
\tif (!this.delayedSelection && this.graph.isCellMovable(initialCell))
\t{
\t\treturn [initialCell];
\t}
\telse
\t{
\t\treturn this.graph.getMovableCells(this.graph.getSelectionCells());
\t}
};

/**
 * Function: getPreviewBounds
 * 
 * Returns the <mxRectangle> used as the preview bounds for
 * moving the given cells.
 */
mxGraphHandler.prototype.getPreviewBounds = function(cells)
{
\tvar bounds = this.getBoundingBox(cells);
\t
\tif (bounds != null)
\t{
\t\t// Corrects width and height
\t\tbounds.width = Math.max(0, bounds.width - 1);
\t\tbounds.height = Math.max(0, bounds.height - 1);
\t\t
\t\tif (bounds.width < this.minimumSize)
\t\t{
\t\t\tvar dx = this.minimumSize - bounds.width;
\t\t\tbounds.x -= dx / 2;
\t\t\tbounds.width = this.minimumSize;
\t\t}
\t\telse
\t\t{
\t\t\tbounds.x = Math.round(bounds.x);
\t\t\tbounds.width = Math.ceil(bounds.width);
\t\t}
\t\t
\t\tvar tr = this.graph.view.translate;
\t\tvar s = this.graph.view.scale;
\t\t
\t\tif (bounds.height < this.minimumSize)
\t\t{
\t\t\tvar dy = this.minimumSize - bounds.height;
\t\t\tbounds.y -= dy / 2;
\t\t\tbounds.height = this.minimumSize;
\t\t}
\t\telse
\t\t{
\t\t\tbounds.y = Math.round(bounds.y);
\t\t\tbounds.height = Math.ceil(bounds.height);
\t\t}
\t}
\t
\treturn bounds;
};

/**
 * Function: getBoundingBox
 * 
 * Returns the union of the <mxCellStates> for the given array of <mxCells>.
 * For vertices, this method uses the bounding box of the corresponding shape
 * if one exists. The bounding box of the corresponding text label and all
 * controls and overlays are ignored. See also: <mxGraphView.getBounds> and
 * <mxGraph.getBoundingBox>.
 *
 * Parameters:
 *
 * cells - Array of <mxCells> whose bounding box should be returned.
 */
mxGraphHandler.prototype.getBoundingBox = function(cells)
{
\tvar result = null;
\t
\tif (cells != null && cells.length > 0)
\t{
\t\tvar model = this.graph.getModel();
\t\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tif (model.isVertex(cells[i]) || model.isEdge(cells[i]))
\t\t\t{
\t\t\t\tvar state = this.graph.view.getState(cells[i]);
\t\t\t
\t\t\t\tif (state != null)
\t\t\t\t{
\t\t\t\t\tvar bbox = state;
\t\t\t\t\t
\t\t\t\t\tif (model.isVertex(cells[i]) && state.shape != null && state.shape.boundingBox != null)
\t\t\t\t\t{
\t\t\t\t\t\tbbox = state.shape.boundingBox;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (result == null)
\t\t\t\t\t{
\t\t\t\t\t\tresult = mxRectangle.fromRectangle(bbox);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tresult.add(bbox);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn result;
};

/**
 * Function: createPreviewShape
 * 
 * Creates the shape used to draw the preview for the given bounds.
 */
mxGraphHandler.prototype.createPreviewShape = function(bounds)
{
\tvar shape = new mxRectangleShape(bounds, null, this.previewColor);
\tshape.isDashed = true;
\t
\tif (this.htmlPreview)
\t{
\t\tshape.dialect = mxConstants.DIALECT_STRICTHTML;
\t\tshape.init(this.graph.container);
\t}
\telse
\t{
\t\t// Makes sure to use either VML or SVG shapes in order to implement
\t\t// event-transparency on the background area of the rectangle since
\t\t// HTML shapes do not let mouseevents through even when transparent
\t\tshape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\tmxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\t\tshape.init(this.graph.getView().getOverlayPane());
\t\tshape.pointerEvents = false;
\t\t
\t\t// Workaround for artifacts on iOS
\t\tif (mxClient.IS_IOS)
\t\t{
\t\t\tshape.getSvgScreenOffset = function()
\t\t\t{
\t\t\t\treturn 0;
\t\t\t};
\t\t}
\t}
\t
\treturn shape;
};

/**
 * Function: start
 * 
 * Starts the handling of the mouse gesture.
 */
mxGraphHandler.prototype.start = function(cell, x, y, cells)
{
\tthis.cell = cell;
\tthis.first = mxUtils.convertPoint(this.graph.container, x, y);
\tthis.cells = (cells != null) ? cells : this.getCells(this.cell);
\tthis.bounds = this.graph.getView().getBounds(this.cells);
\tthis.pBounds = this.getPreviewBounds(this.cells);
\tthis.allCells = new mxDictionary();
\tthis.cloning = false;
\tthis.cellCount = 0;
\t
\tfor (var i = 0; i < this.cells.length; i++)
\t{
\t\tthis.cellCount += this.addStates(this.cells[i], this.allCells);
\t}
\t
\tif (this.guidesEnabled)
\t{
\t\tthis.guide = new mxGuide(this.graph, this.getGuideStates());
\t\tvar parent = this.graph.model.getParent(cell);
\t\tvar ignore = this.graph.model.getChildCount(parent) < 2;
\t\t
\t\t// Uses connected states as guides
\t\tvar connected = new mxDictionary();
\t\tvar opps = this.graph.getOpposites(this.graph.getEdges(this.cell), this.cell);
\t\t
\t\tfor (var i = 0; i < opps.length; i++)
\t\t{
\t\t\tvar state = this.graph.view.getState(opps[i]);
\t\t\t
\t\t\tif (state != null && !connected.get(state))
\t\t\t{
\t\t\t\tconnected.put(state, true);
\t\t\t}
\t\t}

\t\tthis.guide.isStateIgnored = mxUtils.bind(this, function(state)
\t\t{
\t\t\tvar p = this.graph.model.getParent(state.cell);
\t\t\t
\t\t\treturn state.cell != null && ((!this.cloning &&
\t\t\t\tthis.isCellMoving(state.cell)) ||
\t\t\t\t(state.cell != (this.target || parent) && !ignore &&
\t\t\t\t!connected.get(state) &&
\t\t\t\t(this.target == null || this.graph.model.getChildCount(
\t\t\t\tthis.target) >= 2) && p != (this.target || parent)));  
\t\t});
\t}
};

/**
 * Function: addStates
 * 
 * Adds the states for the given cell recursively to the given dictionary.
 */
mxGraphHandler.prototype.addStates = function(cell, dict)
{
\tvar state = this.graph.view.getState(cell);
\tvar count = 0;
\t
\tif (state != null && dict.get(cell) == null)
\t{
\t\tdict.put(cell, state);
\t\tcount++;
\t\t
\t\tvar childCount = this.graph.model.getChildCount(cell);
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tcount += this.addStates(this.graph.model.getChildAt(cell, i), dict);
\t\t}
\t}
\t
\treturn count;
};

/**
 * Function: isCellMoving
 * 
 * Returns true if the given cell is currently being moved.
 */
mxGraphHandler.prototype.isCellMoving = function(cell)
{
\treturn this.allCells.get(cell) != null;
};

/**
 * Function: useGuidesForEvent
 * 
 * Returns true if the guides should be used for the given <mxMouseEvent>.
 * This implementation returns <mxGuide.isEnabledForEvent>.
 */
mxGraphHandler.prototype.useGuidesForEvent = function(me)
{
\treturn (this.guide != null) ? this.guide.isEnabledForEvent(me.getEvent()) &&
\t\t!this.graph.isConstrainedEvent(me.getEvent()) : true;
};


/**
 * Function: snap
 * 
 * Snaps the given vector to the grid and returns the given mxPoint instance.
 */
mxGraphHandler.prototype.snap = function(vector)
{
\tvar scale = (this.scaleGrid) ? this.graph.view.scale : 1;
\t
\tvector.x = this.graph.snap(vector.x / scale) * scale;
\tvector.y = this.graph.snap(vector.y / scale) * scale;
\t
\treturn vector;
};

/**
 * Function: getDelta
 * 
 * Returns an <mxPoint> that represents the vector for moving the cells
 * for the given <mxMouseEvent>.
 */
mxGraphHandler.prototype.getDelta = function(me)
{
\tvar point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
\t
\treturn new mxPoint(point.x - this.first.x - this.graph.panDx,
\t\tpoint.y - this.first.y - this.graph.panDy);
};

/**
 * Function: updateHint
 * 
 * Hook for subclassers do show details while the handler is active.
 */
mxGraphHandler.prototype.updateHint = function(me) { };

/**
 * Function: removeHint
 * 
 * Hooks for subclassers to hide details when the handler gets inactive.
 */
mxGraphHandler.prototype.removeHint = function() { };

/**
 * Function: roundLength
 * 
 * Hook for rounding the unscaled vector. Allows for half steps in the raster so
 * numbers coming in should be rounded if no half steps are allowed (ie for non
 * aligned standard moving where pixel steps should be preferred).
 */
mxGraphHandler.prototype.roundLength = function(length)
{
\treturn Math.round(length * 100) / 100;
};

/**
 * Function: isValidDropTarget
 * 
 * Returns true if the given cell is a valid drop target.
 */
mxGraphHandler.prototype.isValidDropTarget = function(target, me)
{
\treturn this.graph.model.getParent(this.cell) != target;
};

/**
 * Function: checkPreview
 * 
 * Updates the preview if cloning state has changed.
 */
mxGraphHandler.prototype.checkPreview = function()
{
\tif (this.livePreviewActive && this.cloning)
\t{
\t\tthis.resetLivePreview();
\t\tthis.livePreviewActive = false;
\t}
\telse if (this.maxLivePreview >= this.cellCount && !this.livePreviewActive && this.allowLivePreview)
\t{
\t\tif (!this.cloning || !this.livePreviewActive)
\t\t{
\t\t\tthis.livePreviewActive = true;
\t\t\tthis.livePreviewUsed = true;
\t\t}
\t}
\telse if (!this.livePreviewUsed && this.shape == null)
\t{
\t\tthis.shape = this.createPreviewShape(this.bounds);
\t}
};

/**
 * Function: mouseMove
 * 
 * Handles the event by highlighting possible drop targets and updating the
 * preview.
 */
mxGraphHandler.prototype.mouseMove = function(sender, me)
{
\tvar graph = this.graph;

\tif (!me.isConsumed() && graph.isMouseDown && this.cell != null &&
\t\tthis.first != null && this.bounds != null && !this.suspended)
\t{
\t\t// Stops moving if a multi touch event is received
\t\tif (mxEvent.isMultiTouchEvent(me.getEvent()))
\t\t{
\t\t\tthis.reset();
\t\t\treturn;
\t\t}
\t\t
\t\tvar delta = this.getDelta(me);
\t\tvar tol = graph.tolerance;

\t\tif (this.shape != null || this.livePreviewActive || Math.abs(delta.x) > tol || Math.abs(delta.y) > tol)
\t\t{
\t\t\t// Highlight is used for highlighting drop targets
\t\t\tif (this.highlight == null)
\t\t\t{
\t\t\t\tthis.highlight = new mxCellHighlight(this.graph,
\t\t\t\t\tmxConstants.DROP_TARGET_COLOR, 3);
\t\t\t}

\t\t\tvar clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
\t\t\tvar gridEnabled = graph.isGridEnabledEvent(me.getEvent());
\t\t\tvar cell = me.getCell();
\t\t\tvar hideGuide = true;
\t\t\tvar target = null;
\t\t\tthis.cloning = clone;
\t\t\t
\t\t\tif (graph.isDropEnabled() && this.highlightEnabled)
\t\t\t{
\t\t\t\t// Contains a call to getCellAt to find the cell under the mouse
\t\t\t\ttarget = graph.getDropTarget(this.cells, me.getEvent(), cell, clone);
\t\t\t}

\t\t\tvar state = graph.getView().getState(target);
\t\t\tvar highlight = false;
\t\t\t
\t\t\tif (state != null && (clone || this.isValidDropTarget(target, me)))
\t\t\t{
\t\t\t    if (this.target != target)
\t\t\t    {
\t\t\t\t    this.target = target;
\t\t\t\t    this.setHighlightColor(mxConstants.DROP_TARGET_COLOR);
\t\t\t\t}
\t\t\t    
\t\t\t    highlight = true;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.target = null;

\t\t\t\tif (this.connectOnDrop && cell != null && this.cells.length == 1 &&
\t\t\t\t\tgraph.getModel().isVertex(cell) && graph.isCellConnectable(cell))
\t\t\t\t{
\t\t\t\t\tstate = graph.getView().getState(cell);
\t\t\t\t\t
\t\t\t\t\tif (state != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar error = graph.getEdgeValidationError(null, this.cell, cell);
\t\t\t\t\t\tvar color = (error == null) ?
\t\t\t\t\t\t\tmxConstants.VALID_COLOR :
\t\t\t\t\t\t\tmxConstants.INVALID_CONNECT_TARGET_COLOR;
\t\t\t\t\t\tthis.setHighlightColor(color);
\t\t\t\t\t\thighlight = true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (state != null && highlight)
\t\t\t{
\t\t\t\tthis.highlight.highlight(state);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.highlight.hide();
\t\t\t}

\t\t\tif (this.guide != null && this.useGuidesForEvent(me))
\t\t\t{
\t\t\t\tdelta = this.guide.move(this.bounds, delta, gridEnabled, clone);
\t\t\t\thideGuide = false;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tdelta = this.graph.snapDelta(delta, this.bounds, !gridEnabled, false, false);
\t\t\t}
\t\t\t
\t\t\tif (this.guide != null && hideGuide)
\t\t\t{
\t\t\t\tthis.guide.hide();
\t\t\t}

\t\t\t// Constrained movement if shift key is pressed
\t\t\tif (graph.isConstrainedEvent(me.getEvent()))
\t\t\t{
\t\t\t\tif (Math.abs(delta.x) > Math.abs(delta.y))
\t\t\t\t{
\t\t\t\t\tdelta.y = 0;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tdelta.x = 0;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tthis.checkPreview();
\t\t\t
\t\t\tif (this.currentDx != delta.x || this.currentDy != delta.y)
\t\t\t{
\t\t\t\tthis.currentDx = delta.x;
\t\t\t\tthis.currentDy = delta.y;
\t\t\t\tthis.updatePreview();
\t\t\t}
\t\t}

\t\tthis.updateHint(me);
\t\tthis.consumeMouseEvent(mxEvent.MOUSE_MOVE, me);
\t\t
\t\t// Cancels the bubbling of events to the container so
\t\t// that the droptarget is not reset due to an mouseMove
\t\t// fired on the container with no associated state.
\t\tmxEvent.consume(me.getEvent());
\t}
\telse if ((this.isMoveEnabled() || this.isCloneEnabled()) && this.updateCursor && !me.isConsumed() &&
\t\t\t(me.getState() != null || me.sourceState != null) && !graph.isMouseDown)
\t{
\t\tvar cursor = graph.getCursorForMouseEvent(me);
\t\t
\t\tif (cursor == null && graph.isEnabled() && graph.isCellMovable(me.getCell()))
\t\t{
\t\t\tif (graph.getModel().isEdge(me.getCell()))
\t\t\t{
\t\t\t\tcursor = mxConstants.CURSOR_MOVABLE_EDGE;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tcursor = mxConstants.CURSOR_MOVABLE_VERTEX;
\t\t\t}
\t\t}

\t\t// Sets the cursor on the original source state under the mouse
\t\t// instead of the event source state which can be the parent
\t\tif (cursor != null && me.sourceState != null)
\t\t{
\t\t\tme.sourceState.setCursor(cursor);
\t\t}
\t}
};

/**
 * Function: updatePreview
 * 
 * Updates the bounds of the preview shape.
 */
mxGraphHandler.prototype.updatePreview = function(remote)
{
\tif (this.livePreviewUsed && !remote)
\t{
\t\tif (this.cells != null)
\t\t{
\t\t\tthis.setHandlesVisibleForCells(
\t\t\t\tthis.graph.selectionCellsHandler.
\t\t\t\tgetHandledSelectionCells(), false);
\t\t\tthis.updateLivePreview(this.currentDx, this.currentDy);
\t\t}
\t}
\telse
\t{
\t\tthis.updatePreviewShape();
\t}
};

/**
 * Function: updatePreviewShape
 * 
 * Updates the bounds of the preview shape.
 */
mxGraphHandler.prototype.updatePreviewShape = function()
{
\tif (this.shape != null && this.pBounds != null)
\t{
\t\tthis.shape.bounds = new mxRectangle(Math.round(this.pBounds.x + this.currentDx),
\t\t\t\tMath.round(this.pBounds.y + this.currentDy), this.pBounds.width, this.pBounds.height);
\t\tthis.shape.redraw();
\t}
};

/**
 * Function: updateLivePreview
 * 
 * Updates the bounds of the preview shape.
 */
mxGraphHandler.prototype.updateLivePreview = function(dx, dy)
{
\tif (!this.suspended)
\t{
\t\tvar states = [];
\t\t
\t\tif (this.allCells != null)
\t\t{
\t\t\tthis.allCells.visit(mxUtils.bind(this, function(key, state)
\t\t\t{
\t\t\t\tvar realState = this.graph.view.getState(state.cell);
\t\t\t\t
\t\t\t\t// Checks if cell was removed or replaced
\t\t\t\tif (realState != state)
\t\t\t\t{
\t\t\t\t\tstate.destroy();
\t\t\t\t\t
\t\t\t\t\tif (realState != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.allCells.put(state.cell, realState);
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tthis.allCells.remove(state.cell);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tstate = realState;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (state != null)
\t\t\t\t{
\t\t\t\t\t// Saves current state
\t\t\t\t\tvar tempState = state.clone();
\t\t\t\t\tstates.push([state, tempState]);
\t\t
\t\t\t\t\t// Makes transparent for events to detect drop targets
\t\t\t\t\tif (state.shape != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (state.shape.originalPointerEvents == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tstate.shape.originalPointerEvents = state.shape.pointerEvents;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tstate.shape.pointerEvents = false;
\t\t
\t\t\t\t\t\tif (state.text != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (state.text.originalPointerEvents == null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.text.originalPointerEvents = state.text.pointerEvents;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t\tstate.text.pointerEvents = false;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t
\t\t\t\t\t// Temporarily changes position
\t\t\t\t\tif (this.graph.model.isVertex(state.cell))
\t\t\t\t\t{
\t\t\t\t\t\tstate.x += dx;
\t\t\t\t\t\tstate.y += dy;
\t\t\t\t\t\t
\t\t\t\t\t\t// Draws the live preview
\t\t\t\t\t\tif (!this.cloning)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tstate.view.graph.cellRenderer.redraw(state, true);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Forces redraw of connected edges after all states
\t\t\t\t\t\t\t// have been updated but avoids update of state
\t\t\t\t\t\t\tstate.view.invalidate(state.cell);
\t\t\t\t\t\t\tstate.invalid = false;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Hides folding icon
\t\t\t\t\t\t\tif (state.control != null && state.control.node != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.control.node.style.visibility = 'hidden';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t// Clone live preview may use text bounds
\t\t\t\t\t\telse if (state.text != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tstate.text.updateBoundingBox();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Fixes preview box for edge labels
\t\t\t\t\t\t\tif (state.text.boundingBox != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.text.boundingBox.x += dx;
\t\t\t\t\t\t\t\tstate.text.boundingBox.y += dy;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (state.text.unrotatedBoundingBox != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tstate.text.unrotatedBoundingBox.x += dx;
\t\t\t\t\t\t\t\tstate.text.unrotatedBoundingBox.y += dy;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}));
\t\t}
\t\t
\t\t// Resets the handler if everything was removed
\t\tif (states.length == 0)
\t\t{
\t\t\tthis.reset();
\t\t}
\t\telse
\t\t{
\t\t\t// Redraws connected edges
\t\t\tvar s = this.graph.view.scale;
\t\t\t
\t\t\tfor (var i = 0; i < states.length; i++)
\t\t\t{
\t\t\t\tvar state = states[i][0];
\t\t\t\t
\t\t\t\tif (this.graph.model.isEdge(state.cell))
\t\t\t\t{
\t\t\t\t\tvar geometry = this.graph.getCellGeometry(state.cell);
\t\t\t\t\tvar points = [];
\t\t\t\t\t
\t\t\t\t\tif (geometry != null && geometry.points != null)
\t\t\t\t\t{
\t\t\t\t\t\tfor (var j = 0; j < geometry.points.length; j++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (geometry.points[j] != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tpoints.push(new mxPoint(
\t\t\t\t\t\t\t\t\tgeometry.points[j].x + dx / s,
\t\t\t\t\t\t\t\t\tgeometry.points[j].y + dy / s));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t
\t\t\t\t\tvar source = state.visibleSourceState;
\t\t\t\t\tvar target = state.visibleTargetState;
\t\t\t\t\tvar pts = states[i][1].absolutePoints;
\t\t\t\t\t
\t\t\t\t\tif (source == null || !this.isCellMoving(source.cell))
\t\t\t\t\t{
\t\t\t\t\t\tvar pt0 = pts[0];
\t\t\t\t\t\tstate.setAbsoluteTerminalPoint(new mxPoint(pt0.x + dx, pt0.y + dy), true);
\t\t\t\t\t\tsource = null;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tstate.view.updateFixedTerminalPoint(state, source, true,
\t\t\t\t\t\t\tthis.graph.getConnectionConstraint(state, source, true));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (target == null || !this.isCellMoving(target.cell))
\t\t\t\t\t{
\t\t\t\t\t\tvar ptn = pts[pts.length - 1];
\t\t\t\t\t\tstate.setAbsoluteTerminalPoint(new mxPoint(ptn.x + dx, ptn.y + dy), false);
\t\t\t\t\t\ttarget = null;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tstate.view.updateFixedTerminalPoint(state, target, false,
\t\t\t\t\t\t\tthis.graph.getConnectionConstraint(state, target, false));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tstate.view.updatePoints(state, points, source, target);
\t\t\t\t\tstate.view.updateFloatingTerminalPoints(state, source, target);
\t\t\t\t\tstate.view.updateEdgeLabelOffset(state);
\t\t\t\t\tstate.invalid = false;
\t
\t\t\t\t\t// Draws the live preview but avoids update of state
\t\t\t\t\tif (!this.cloning)
\t\t\t\t\t{
\t\t\t\t\t\tstate.view.graph.cellRenderer.redraw(state, true);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t
\t\t\tthis.graph.view.validate();
\t\t\tthis.redrawHandles(states);
\t\t\tthis.resetPreviewStates(states);
\t\t}
\t}
};

/**
 * Function: redrawHandles
 * 
 * Redraws the preview shape for the given states array.
 */
mxGraphHandler.prototype.redrawHandles = function(states)
{
\tfor (var i = 0; i < states.length; i++)
\t{
\t\tvar handler = this.graph.selectionCellsHandler.getHandler(states[i][0].cell);
\t\t
\t\tif (handler != null)
\t\t{
\t\t\thandler.redraw(true);
\t\t}
\t}
};

/**
 * Function: resetPreviewStates
 * 
 * Resets the given preview states array.
 */
mxGraphHandler.prototype.resetPreviewStates = function(states)
{
\tfor (var i = 0; i < states.length; i++)
\t{
\t\tstates[i][0].setState(states[i][1]);
\t}
};

/**
 * Function: suspend
 * 
 * Suspends the livew preview.
 */
mxGraphHandler.prototype.suspend = function()
{
\tif (!this.suspended)
\t{
\t\tif (this.livePreviewUsed)
\t\t{
\t\t\tthis.updateLivePreview(0, 0);
\t\t}
\t\t
\t\tif (this.shape != null)
\t\t{
\t\t\tthis.shape.node.style.visibility = 'hidden';
\t\t} 
\t
\t\tif (this.guide != null)
\t\t{
\t\t\tthis.guide.setVisible(false);
\t\t}
\t\t
\t\tthis.suspended = true;
\t}
};

/**
 * Function: resume
 * 
 * Suspends the livew preview.
 */
mxGraphHandler.prototype.resume = function()
{
\tif (this.suspended)
\t{
\t\tthis.suspended = null;
\t\t
\t\tif (this.livePreviewUsed)
\t\t{
\t\t\tthis.livePreviewActive = true;
\t\t}
\t\t
\t\tif (this.shape != null)
\t\t{
\t\t\tthis.shape.node.style.visibility = 'visible';
\t\t}
\t\t
\t\tif (this.guide != null)
\t\t{
\t\t\tthis.guide.setVisible(true);
\t\t}
\t}
};

/**
 * Function: resetLivePreview
 * 
 * Resets the livew preview.
 */
mxGraphHandler.prototype.resetLivePreview = function()
{
\tif (this.allCells != null)
\t{
\t\tthis.allCells.visit(mxUtils.bind(this, function(key, state)
\t\t{
\t\t\t// Restores event handling
\t\t\tif (state.shape != null && state.shape.originalPointerEvents != null)
\t\t\t{
\t\t\t\tstate.shape.pointerEvents = state.shape.originalPointerEvents;
\t\t\t\tstate.shape.originalPointerEvents = null;
\t\t\t\t
\t\t\t\t// Forces repaint even if not moved to update pointer events
\t\t\t\tstate.shape.bounds = null;
\t\t\t\t
\t\t\t\tif (state.text != null)
\t\t\t\t{
\t\t\t\t\tstate.text.pointerEvents = state.text.originalPointerEvents;
\t\t\t\t\tstate.text.originalPointerEvents = null;
\t\t\t\t}
\t\t\t}

\t\t\t// Shows folding icon
\t\t\tif (state.control != null && state.control.node != null &&
\t\t\t\tstate.control.node.style.visibility == 'hidden')
\t\t\t{
\t\t\t\tstate.control.node.style.visibility = '';
\t\t\t}
\t\t\t
\t\t\t// Fixes preview box for edge labels
\t\t\tif (!this.cloning)
\t\t\t{
\t\t\t\tif (state.text != null)
\t\t\t\t{
\t\t\t\t\tstate.text.updateBoundingBox();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Forces repaint of connected edges
\t\t\tstate.view.invalidate(state.cell);
\t\t}));

\t\t// Repaints all invalid states
\t\tthis.graph.view.validate();
\t}
};

/**
 * Function: setHandlesVisibleForCells
 * 
 * Sets wether the handles attached to the given cells are visible.
 * 
 * Parameters:
 * 
 * cells - Array of <mxCells>.
 * visible - Boolean that specifies if the handles should be visible.
 * force - Forces an update of the handler regardless of the last used value.
 */
mxGraphHandler.prototype.setHandlesVisibleForCells = function(cells, visible, force)
{
\tif (force || this.handlesVisible != visible)
\t{
\t\tthis.handlesVisible = visible;
\t
\t\tfor (var i = 0; i < cells.length; i++)
\t\t{
\t\t\tvar handler = this.graph.selectionCellsHandler.getHandler(cells[i]);
\t\t\t
\t\t\tif (handler != null)
\t\t\t{
\t\t\t\thandler.setHandlesVisible(visible);
\t\t\t\t
\t\t\t\tif (visible)
\t\t\t\t{
\t\t\t\t\thandler.redraw();
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: setHighlightColor
 * 
 * Sets the color of the rectangle used to highlight drop targets.
 * 
 * Parameters:
 * 
 * color - String that represents the new highlight color.
 */
mxGraphHandler.prototype.setHighlightColor = function(color)
{
\tif (this.highlight != null)
\t{
\t\tthis.highlight.setHighlightColor(color);
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event by applying the changes to the selection cells.
 */
mxGraphHandler.prototype.mouseUp = function(sender, me)
{
\tif (!me.isConsumed())
\t{
\t\tif (this.livePreviewUsed)
\t\t{
\t\t\tthis.resetLivePreview();
\t\t}
\t\t
\t\tif (this.cell != null && this.first != null && (this.shape != null || this.livePreviewUsed) &&
\t\t\tthis.currentDx != null && this.currentDy != null)
\t\t{
\t\t\tvar graph = this.graph;
\t\t\tvar cell = me.getCell();
\t\t\t
\t\t\tif (this.connectOnDrop && this.target == null && cell != null && graph.getModel().isVertex(cell) &&
\t\t\t\tgraph.isCellConnectable(cell) && graph.isEdgeValid(null, this.cell, cell))
\t\t\t{
\t\t\t\tgraph.connectionHandler.connect(this.cell, cell, me.getEvent());
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
\t\t\t\tvar scale = graph.getView().scale;
\t\t\t\tvar dx = this.roundLength(this.currentDx / scale);
\t\t\t\tvar dy = this.roundLength(this.currentDy / scale);
\t\t\t\tvar target = this.target;
\t\t\t\t
\t\t\t\tif (graph.isSplitEnabled() && graph.isSplitTarget(target, this.cells, me.getEvent()))
\t\t\t\t{
\t\t\t\t\tgraph.splitEdge(target, this.cells, null, dx, dy,
\t\t\t\t\t\tme.getGraphX(), me.getGraphY());
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.moveCells(this.cells, dx, dy, clone, this.target, me.getEvent());
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (this.isSelectEnabled() && this.delayedSelection && this.cell != null)
\t\t{
\t\t\tthis.selectDelayed(me);
\t\t}
\t}

\t// Consumes the event if a cell was initially clicked
\tif (this.cellWasClicked)
\t{
\t\tthis.consumeMouseEvent(mxEvent.MOUSE_UP, me);
\t}

\tthis.reset();
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxGraphHandler.prototype.reset = function()
{
\tif (this.livePreviewUsed)
\t{
\t\tthis.resetLivePreview();
\t\tthis.setHandlesVisibleForCells(
\t\t\tthis.graph.selectionCellsHandler.
\t\t\tgetHandledSelectionCells(), true);
\t}
\t
\tthis.destroyShapes();
\tthis.removeHint();

\tthis.delayedSelection = false;
\tthis.livePreviewActive = null;
\tthis.livePreviewUsed = null;
\tthis.cellWasClicked = false;
\tthis.suspended = null;
\tthis.currentDx = null;
\tthis.currentDy = null;
\tthis.cellCount = null;
\tthis.cloning = false;
\tthis.allCells = null;
\tthis.pBounds = null;
\tthis.guides = null;
\tthis.target = null;
\tthis.first = null;
\tthis.cells = null;
\tthis.cell = null;
};

/**
 * Function: shouldRemoveCellsFromParent
 * 
 * Returns true if the given cells should be removed from the parent for the specified
 * mousereleased event.
 */
mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
{
\tif (this.graph.getModel().isVertex(parent))
\t{
\t\tvar pState = this.graph.getView().getState(parent);
\t\t
\t\tif (pState != null)
\t\t{
\t\t\tvar pt = mxUtils.convertPoint(this.graph.container,
\t\t\t\tmxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t\t\tvar alpha = mxUtils.toRadians(mxUtils.getValue(pState.style, mxConstants.STYLE_ROTATION) || 0);
\t\t\t
\t\t\tif (alpha != 0)
\t\t\t{
\t\t\t\tvar cos = Math.cos(-alpha);
\t\t\t\tvar sin = Math.sin(-alpha);
\t\t\t\tvar cx = new mxPoint(pState.getCenterX(), pState.getCenterY());
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, cx);
\t\t\t}
\t\t
\t\t\treturn !mxUtils.contains(pState, pt.x, pt.y);
\t\t}
\t}
\t
\treturn false;
};

/**
 * Function: moveCells
 * 
 * Moves the given cells by the specified amount.
 */
mxGraphHandler.prototype.moveCells = function(cells, dx, dy, clone, target, evt)
{
\tif (clone)
\t{
\t\tcells = this.graph.getCloneableCells(cells);
\t}
\t
\t// Removes cells from parent
\tvar parent = this.graph.getModel().getParent(this.cell);
\t
\tif (target == null && this.isRemoveCellsFromParent() &&
\t\tthis.shouldRemoveCellsFromParent(parent, cells, evt))
\t{
\t\ttarget = this.graph.getDefaultParent();
\t}
\t
\t// Cloning into locked cells is not allowed
\tclone = clone && !this.graph.isCellLocked(target || this.graph.getDefaultParent());

\tthis.graph.getModel().beginUpdate();
\ttry
\t{
\t\tvar parents = [];
\t\t
\t\t// Removes parent if all child cells are removed
\t\tif (!clone && target != null && this.removeEmptyParents)
\t\t{
\t\t\t// Collects all non-selected parents
\t\t\tvar dict = new mxDictionary();
\t\t\t
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tdict.put(cells[i], true);
\t\t\t}
\t\t\t
\t\t\t// LATER: Recurse up the cell hierarchy
\t\t\tfor (var i = 0; i < cells.length; i++)
\t\t\t{
\t\t\t\tvar par = this.graph.model.getParent(cells[i]);

\t\t\t\tif (par != null && !dict.get(par))
\t\t\t\t{
\t\t\t\t\tdict.put(par, true);
\t\t\t\t\tparents.push(par);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\t// Passes all selected cells in order to correctly clone or move into
\t\t// the target cell. The method checks for each cell if its movable.
\t\tcells = this.graph.moveCells(cells, dx, dy, clone, target, evt);

\t\t// Removes parent if all child cells are removed
\t\tvar temp = [];
\t\t
\t\tfor (var i = 0; i < parents.length; i++)
\t\t{
\t\t\tif (this.shouldRemoveParent(parents[i]))
\t\t\t{
\t\t\t\ttemp.push(parents[i]);
\t\t\t}
\t\t}
\t\t
\t\tthis.graph.removeCells(temp, false);
\t}
\tfinally
\t{
\t\tthis.graph.getModel().endUpdate();
\t}

\t// Selects the new cells if cells have been cloned
\tif (clone)
\t{
\t\tthis.graph.setSelectionCells(cells);
\t}

\tif (this.isSelectEnabled() && this.scrollOnMove)
\t{
\t\tthis.graph.scrollCellToVisible(cells[0]);
\t}
};

/**
 * Function: shouldRemoveParent
 * 
 * Returns true if the given parent should be removed after removal of child cells.
 */
mxGraphHandler.prototype.shouldRemoveParent = function(parent)
{
\tvar state = this.graph.view.getState(parent);
\t
\treturn state != null && (this.graph.model.isEdge(state.cell) || this.graph.model.isVertex(state.cell)) &&
\t\tthis.graph.isCellDeletable(state.cell) && this.graph.model.getChildCount(state.cell) == 0 &&
\t\tthis.graph.isTransparentState(state);
};

/**
 * Function: destroyShapes
 * 
 * Destroy the preview and highlight shapes.
 */
mxGraphHandler.prototype.destroyShapes = function()
{
\t// Destroys the preview dashed rectangle
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
\t
\tif (this.guide != null)
\t{
\t\tthis.guide.destroy();
\t\tthis.guide = null;
\t}
\t
\t// Destroys the drop target highlight
\tif (this.highlight != null)
\t{
\t\tthis.highlight.destroy();
\t\tthis.highlight = null;
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxGraphHandler.prototype.destroy = function()
{
\tthis.graph.removeMouseListener(this);
\tthis.graph.removeListener(this.panHandler);
\t
\tif (this.escapeHandler != null)
\t{
\t\tthis.graph.removeListener(this.escapeHandler);
\t\tthis.escapeHandler = null;
\t}
\t
\tif (this.refreshHandler != null)
\t{
\t\tthis.graph.getModel().removeListener(this.refreshHandler);
\t\tthis.graph.removeListener(this.refreshHandler);
\t\tthis.refreshHandler = null;
\t}
\t
\tmxEvent.removeListener(document, 'keydown', this.keyHandler);
\tmxEvent.removeListener(document, 'keyup', this.keyHandler);
\t
\tthis.destroyShapes();
\tthis.removeHint();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPanningHandler
 * 
 * Event handler that pans and creates popupmenus. To use the left
 * mousebutton for panning without interfering with cell moving and
 * resizing, use <isUseLeftButton> and <isIgnoreCell>. For grid size
 * steps while panning, use <useGrid>. This handler is built-into
 * <mxGraph.panningHandler> and enabled using <mxGraph.setPanning>.
 * 
 * Constructor: mxPanningHandler
 * 
 * Constructs an event handler that creates a <mxPopupMenu>
 * and pans the graph.
 *
 * Event: mxEvent.PAN_START
 *
 * Fires when the panning handler changes its <active> state to true. The
 * <code>event</code> property contains the corresponding <mxMouseEvent>.
 *
 * Event: mxEvent.PAN
 *
 * Fires while handle is processing events. The <code>event</code> property contains
 * the corresponding <mxMouseEvent>.
 *
 * Event: mxEvent.PAN_END
 *
 * Fires when the panning handler changes its <active> state to false. The
 * <code>event</code> property contains the corresponding <mxMouseEvent>.
 */
function mxPanningHandler(graph)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.graph.addMouseListener(this);

\t\t// Handles force panning event
\t\tthis.forcePanningHandler = mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tvar evtName = evt.getProperty('eventName');
\t\t\tvar me = evt.getProperty('event');
\t\t\t
\t\t\tif (evtName == mxEvent.MOUSE_DOWN && this.isForcePanningEvent(me))
\t\t\t{
\t\t\t\tthis.start(me);
\t\t\t\tthis.active = true;
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
\t\t\t\tme.consume();
\t\t\t}
\t\t});

\t\tthis.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forcePanningHandler);
\t\t
\t\t// Handles pinch gestures
\t\tthis.gestureHandler = mxUtils.bind(this, function(sender, eo)
\t\t{
\t\t\tif (this.isPinchEnabled())
\t\t\t{
\t\t\t\tvar evt = eo.getProperty('event');
\t\t\t\t
\t\t\t\tif (!mxEvent.isConsumed(evt) && evt.type == 'gesturestart')
\t\t\t\t{
\t\t\t\t\tthis.initialScale = this.graph.view.scale;
\t\t\t\t
\t\t\t\t\t// Forces start of panning when pinch gesture starts
\t\t\t\t\tif (!this.active && this.mouseDownEvent != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.start(this.mouseDownEvent);
\t\t\t\t\t\tthis.mouseDownEvent = null;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (evt.type == 'gestureend' && this.initialScale != null)
\t\t\t\t{
\t\t\t\t\tthis.initialScale = null;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (this.initialScale != null)
\t\t\t\t{
\t\t\t\t\tthis.zoomGraph(evt);
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
\t\t
\t\tthis.mouseUpListener = mxUtils.bind(this, function()
\t\t{
\t    \tif (this.active)
\t    \t{
\t    \t\tthis.reset();
\t    \t}
\t\t});
\t\t
\t\t// Stops scrolling on every mouseup anywhere in the document
\t\tmxEvent.addListener(document, 'mouseup', this.mouseUpListener);
\t}
};

/**
 * Extends mxEventSource.
 */
mxPanningHandler.prototype = new mxEventSource();
mxPanningHandler.prototype.constructor = mxPanningHandler;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxPanningHandler.prototype.graph = null;

/**
 * Variable: useLeftButtonForPanning
 * 
 * Specifies if panning should be active for the left mouse button.
 * Setting this to true may conflict with <mxRubberband>. Default is false.
 */
mxPanningHandler.prototype.useLeftButtonForPanning = false;

/**
 * Variable: usePopupTrigger
 * 
 * Specifies if <mxEvent.isPopupTrigger> should also be used for panning.
 */
mxPanningHandler.prototype.usePopupTrigger = true;

/**
 * Variable: ignoreCell
 * 
 * Specifies if panning should be active even if there is a cell under the
 * mousepointer. Default is false.
 */
mxPanningHandler.prototype.ignoreCell = false;

/**
 * Variable: previewEnabled
 * 
 * Specifies if the panning should be previewed. Default is true.
 */
mxPanningHandler.prototype.previewEnabled = true;

/**
 * Variable: useGrid
 * 
 * Specifies if the panning steps should be aligned to the grid size.
 * Default is false.
 */
mxPanningHandler.prototype.useGrid = false;

/**
 * Variable: panningEnabled
 * 
 * Specifies if panning should be enabled. Default is true.
 */
mxPanningHandler.prototype.panningEnabled = true;

/**
 * Variable: pinchEnabled
 * 
 * Specifies if pinch gestures should be handled as zoom. Default is true.
 */
mxPanningHandler.prototype.pinchEnabled = true;

/**
 * Variable: maxScale
 * 
 * Specifies the maximum scale. Default is 8.
 */
mxPanningHandler.prototype.maxScale = 8;

/**
 * Variable: minScale
 * 
 * Specifies the minimum scale. Default is 0.01.
 */
mxPanningHandler.prototype.minScale = 0.01;

/**
 * Variable: dx
 * 
 * Holds the current horizontal offset.
 */
mxPanningHandler.prototype.dx = null;

/**
 * Variable: dy
 * 
 * Holds the current vertical offset.
 */
mxPanningHandler.prototype.dy = null;

/**
 * Variable: startX
 * 
 * Holds the x-coordinate of the start point.
 */
mxPanningHandler.prototype.startX = 0;

/**
 * Variable: startY
 * 
 * Holds the y-coordinate of the start point.
 */
mxPanningHandler.prototype.startY = 0;

/**
 * Function: isActive
 * 
 * Returns true if the handler is currently active.
 */
mxPanningHandler.prototype.isActive = function()
{
\treturn this.active || this.initialScale != null;
};

/**
 * Function: isPanningEnabled
 * 
 * Returns <panningEnabled>.
 */
mxPanningHandler.prototype.isPanningEnabled = function()
{
\treturn this.panningEnabled;
};

/**
 * Function: setPanningEnabled
 * 
 * Sets <panningEnabled>.
 */
mxPanningHandler.prototype.setPanningEnabled = function(value)
{
\tthis.panningEnabled = value;
};

/**
 * Function: isPinchEnabled
 * 
 * Returns <pinchEnabled>.
 */
mxPanningHandler.prototype.isPinchEnabled = function()
{
\treturn this.pinchEnabled;
};

/**
 * Function: setPinchEnabled
 * 
 * Sets <pinchEnabled>.
 */
mxPanningHandler.prototype.setPinchEnabled = function(value)
{
\tthis.pinchEnabled = value;
};

/**
 * Function: isPanningTrigger
 * 
 * Returns true if the given event is a panning trigger for the optional
 * given cell. This returns true if control-shift is pressed or if
 * <usePopupTrigger> is true and the event is a popup trigger.
 */
mxPanningHandler.prototype.isPanningTrigger = function(me)
{
\tvar evt = me.getEvent();
\t
\treturn (this.useLeftButtonForPanning && me.getState() == null &&
\t\t\tmxEvent.isLeftMouseButton(evt)) || (mxEvent.isControlDown(evt) &&
\t\t\tmxEvent.isShiftDown(evt)) || (this.usePopupTrigger && mxEvent.isPopupTrigger(evt));
};

/**
 * Function: isForcePanningEvent
 * 
 * Returns true if the given <mxMouseEvent> should start panning. This
 * implementation always returns true if <ignoreCell> is true or for
 * multi touch events.
 */
mxPanningHandler.prototype.isForcePanningEvent = function(me)
{
\treturn this.ignoreCell || mxEvent.isMultiTouchEvent(me.getEvent());
};

/**
 * Function: mouseDown
 * 
 * Handles the event by initiating the panning. By consuming the event all
 * subsequent events of the gesture are redirected to this handler.
 */
mxPanningHandler.prototype.mouseDown = function(sender, me)
{
\tthis.mouseDownEvent = me;
\t
\tif (!me.isConsumed() && this.isPanningEnabled() && !this.active && this.isPanningTrigger(me))
\t{
\t\tthis.start(me);
\t\tthis.consumePanningTrigger(me);
\t}
};

/**
 * Function: start
 * 
 * Starts panning at the given event.
 */
mxPanningHandler.prototype.start = function(me)
{
\tthis.dx0 = -this.graph.container.scrollLeft;
\tthis.dy0 = -this.graph.container.scrollTop;

\t// Stores the location of the trigger event
\tthis.startX = me.getX();
\tthis.startY = me.getY();
\tthis.dx = null;
\tthis.dy = null;
\t
\tthis.panningTrigger = true;
};

/**
 * Function: consumePanningTrigger
 * 
 * Consumes the given <mxMouseEvent> if it was a panning trigger in
 * <mouseDown>. The default is to invoke <mxMouseEvent.consume>. Note that this
 * will block any further event processing. If you haven't disabled built-in
 * context menus and require immediate selection of the cell on mouseDown in
 * Safari and/or on the Mac, then use the following code:
 * 
 * (code)
 * mxPanningHandler.prototype.consumePanningTrigger = function(me)
 * {
 *   if (me.evt.preventDefault)
 *   {
 *     me.evt.preventDefault();
 *   }
 *   
 *   // Stops event processing in IE
 *   me.evt.returnValue = false;
 *   
 *   // Sets local consumed state
 *   if (!mxClient.IS_SF && !mxClient.IS_MAC)
 *   {
 *     me.consumed = true;
 *   }
 * };
 * (end)
 */
mxPanningHandler.prototype.consumePanningTrigger = function(me)
{
\tme.consume();
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the panning on the graph.
 */
mxPanningHandler.prototype.mouseMove = function(sender, me)
{
\tthis.dx = me.getX() - this.startX;
\tthis.dy = me.getY() - this.startY;
\t
\tif (this.active)
\t{
\t\tif (this.previewEnabled)
\t\t{
\t\t\t// Applies the grid to the panning steps
\t\t\tif (this.useGrid)
\t\t\t{
\t\t\t\tthis.dx = this.graph.snap(this.dx);
\t\t\t\tthis.dy = this.graph.snap(this.dy);
\t\t\t}
\t\t\t
\t\t\tthis.graph.panGraph(this.dx + this.dx0, this.dy + this.dy0);
\t\t}

\t\tthis.fireEvent(new mxEventObject(mxEvent.PAN, 'event', me));
\t}
\telse if (this.panningTrigger)
\t{
\t\tvar tmp = this.active;

\t\t// Panning is activated only if the mouse is moved
\t\t// beyond the graph tolerance
\t\tthis.active = Math.abs(this.dx) > this.graph.tolerance || Math.abs(this.dy) > this.graph.tolerance;

\t\tif (!tmp && this.active)
\t\t{
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
\t\t}
\t}
\t
\tif (this.active || this.panningTrigger)
\t{
\t\tme.consume();
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event by setting the translation on the view or showing the
 * popupmenu.
 */
mxPanningHandler.prototype.mouseUp = function(sender, me)
{
\tif (this.active)
\t{
\t\tif (this.dx != null && this.dy != null)
\t\t{
\t\t\t// Ignores if scrollbars have been used for panning
\t\t\tif (!this.graph.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.graph.container))
\t\t\t{
\t\t\t\tvar scale = this.graph.getView().scale;
\t\t\t\tvar t = this.graph.getView().translate;
\t\t\t\tthis.graph.panGraph(0, 0);
\t\t\t\tthis.panGraph(t.x + this.dx / scale, t.y + this.dy / scale);
\t\t\t}
\t\t\t
\t\t\tme.consume();
\t\t}
\t\t
\t\tthis.fireEvent(new mxEventObject(mxEvent.PAN_END, 'event', me));
\t}
\t
\tthis.reset();
};

/**
 * Function: zoomGraph
 * 
 * Zooms the graph to the given value and consumed the event if needed.
 */
mxPanningHandler.prototype.zoomGraph = function(evt)
{
\tvar value = Math.round(this.initialScale * evt.scale * 100) / 100;
\t
\tif (this.minScale != null)
\t{
\t\tvalue = Math.max(this.minScale, value);
\t}
\t
\tif (this.maxScale != null)
\t{
\t\tvalue = Math.min(this.maxScale, value);
\t}

\tif (this.graph.view.scale != value)
\t{
\t\tthis.graph.zoomTo(value);
\t\tmxEvent.consume(evt);
\t}
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxPanningHandler.prototype.reset = function()
{
\tthis.panningTrigger = false;
\tthis.mouseDownEvent = null;
\tthis.active = false;
\tthis.dx = null;
\tthis.dy = null;
};

/**
 * Function: panGraph
 * 
 * Pans <graph> by the given amount.
 */
mxPanningHandler.prototype.panGraph = function(dx, dy)
{
\tthis.graph.getView().setTranslate(dx, dy);
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxPanningHandler.prototype.destroy = function()
{
\tthis.graph.removeMouseListener(this);
\tthis.graph.removeListener(this.forcePanningHandler);
\tthis.graph.removeListener(this.gestureHandler);
\tmxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxPopupMenuHandler
 * 
 * Event handler that creates popupmenus.
 * 
 * Constructor: mxPopupMenuHandler
 * 
 * Constructs an event handler that creates a <mxPopupMenu>.
 */
function mxPopupMenuHandler(graph, factoryMethod)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.factoryMethod = factoryMethod;
\t\tthis.graph.addMouseListener(this);
\t\t
\t\t// Does not show menu if any touch gestures take place after the trigger
\t\tthis.gestureHandler = mxUtils.bind(this, function(sender, eo)
\t\t{
\t\t\tthis.inTolerance = false;
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
\t\t
\t\tthis.init();
\t}
};

/**
 * Extends mxPopupMenu.
 */
mxPopupMenuHandler.prototype = new mxPopupMenu();
mxPopupMenuHandler.prototype.constructor = mxPopupMenuHandler;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxPopupMenuHandler.prototype.graph = null;

/**
 * Variable: selectOnPopup
 * 
 * Specifies if cells should be selected if a popupmenu is displayed for
 * them. Default is true.
 */
mxPopupMenuHandler.prototype.selectOnPopup = true;

/**
 * Variable: clearSelectionOnBackground
 * 
 * Specifies if cells should be deselected if a popupmenu is displayed for
 * the diagram background. Default is true.
 */
mxPopupMenuHandler.prototype.clearSelectionOnBackground = true;

/**
 * Variable: triggerX
 * 
 * X-coordinate of the mouse down event.
 */
mxPopupMenuHandler.prototype.triggerX = null;

/**
 * Variable: triggerY
 * 
 * Y-coordinate of the mouse down event.
 */
mxPopupMenuHandler.prototype.triggerY = null;

/**
 * Variable: screenX
 * 
 * Screen X-coordinate of the mouse down event.
 */
mxPopupMenuHandler.prototype.screenX = null;

/**
 * Variable: screenY
 * 
 * Screen Y-coordinate of the mouse down event.
 */
mxPopupMenuHandler.prototype.screenY = null;

/**
 * Function: init
 * 
 * Initializes the shapes required for this vertex handler.
 */
mxPopupMenuHandler.prototype.init = function()
{
\t// Supercall
\tmxPopupMenu.prototype.init.apply(this);

\t// Hides the tooltip if the mouse is over
\t// the context menu
\tmxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
\t{
\t\tthis.graph.tooltipHandler.hide();
\t}));
};

/**
 * Function: isSelectOnPopup
 * 
 * Hook for returning if a cell should be selected for a given <mxMouseEvent>.
 * This implementation returns <selectOnPopup>.
 */
mxPopupMenuHandler.prototype.isSelectOnPopup = function(me)
{
\treturn this.selectOnPopup;
};

/**
 * Function: mouseDown
 * 
 * Handles the event by initiating the panning. By consuming the event all
 * subsequent events of the gesture are redirected to this handler.
 */
mxPopupMenuHandler.prototype.mouseDown = function(sender, me)
{
\tif (this.isEnabled() && !mxEvent.isMultiTouchEvent(me.getEvent()))
\t{
\t\t// Hides the popupmenu if is is being displayed
\t\tthis.hideMenu();
\t\tthis.triggerX = me.getGraphX();
\t\tthis.triggerY = me.getGraphY();
\t\tthis.screenX = mxEvent.getMainEvent(me.getEvent()).screenX;
\t\tthis.screenY = mxEvent.getMainEvent(me.getEvent()).screenY;
\t\tthis.popupTrigger = this.isPopupTrigger(me);
\t\tthis.inTolerance = true;
\t}
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the panning on the graph.
 */
mxPopupMenuHandler.prototype.mouseMove = function(sender, me)
{
\t// Popup trigger may change on mouseUp so ignore it
\tif (this.inTolerance && this.screenX != null && this.screenY != null)
\t{
\t\tif (Math.abs(mxEvent.getMainEvent(me.getEvent()).screenX - this.screenX) > this.graph.tolerance ||
\t\t\tMath.abs(mxEvent.getMainEvent(me.getEvent()).screenY - this.screenY) > this.graph.tolerance)
\t\t{
\t\t\tthis.inTolerance = false;
\t\t}
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event by setting the translation on the view or showing the
 * popupmenu.
 */
mxPopupMenuHandler.prototype.mouseUp = function(sender, me)
{
\tif (this.popupTrigger && this.inTolerance && this.triggerX != null && this.triggerY != null)
\t{
\t\tvar cell = this.getCellForPopupEvent(me);

\t\t// Selects the cell for which the context menu is being displayed
\t\tif (this.graph.isEnabled() && this.isSelectOnPopup(me) &&
\t\t\tcell != null && !this.graph.isCellSelected(cell))
\t\t{
\t\t\tthis.graph.setSelectionCell(cell);
\t\t}
\t\telse if (this.clearSelectionOnBackground && cell == null)
\t\t{
\t\t\tthis.graph.clearSelection();
\t\t}
\t\t
\t\t// Hides the tooltip if there is one
\t\tthis.graph.tooltipHandler.hide();

\t\t// Menu is shifted by 1 pixel so that the mouse up event
\t\t// is routed via the underlying shape instead of the DIV
\t\tvar origin = mxUtils.getScrollOrigin();
\t\tthis.popup(me.getX() + origin.x + 1, me.getY() + origin.y + 1, cell, me.getEvent());
\t\tme.consume();
\t}
\t
\tthis.popupTrigger = false;
\tthis.inTolerance = false;
};

/**
 * Function: getCellForPopupEvent
 * 
 * Hook to return the cell for the mouse up popup trigger handling.
 */
mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
{
\treturn me.getCell();
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxPopupMenuHandler.prototype.destroy = function()
{
\tthis.graph.removeMouseListener(this);
\tthis.graph.removeListener(this.gestureHandler);
\t
\t// Supercall
\tmxPopupMenu.prototype.destroy.apply(this);
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellMarker
 * 
 * A helper class to process mouse locations and highlight cells.
 * 
 * Helper class to highlight cells. To add a cell marker to an existing graph
 * for highlighting all cells, the following code is used:
 * 
 * (code)
 * var marker = new mxCellMarker(graph);
 * graph.addMouseListener({
 *   mouseDown: function() {},
 *   mouseMove: function(sender, me)
 *   {
 *     marker.process(me);
 *   },
 *   mouseUp: function() {}
 * });
 * (end)
 *
 * Event: mxEvent.MARK
 * 
 * Fires after a cell has been marked or unmarked. The <code>state</code>
 * property contains the marked <mxCellState> or null if no state is marked.
 * 
 * Constructor: mxCellMarker
 * 
 * Constructs a new cell marker.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * validColor - Optional marker color for valid states. Default is
 * <mxConstants.DEFAULT_VALID_COLOR>.
 * invalidColor - Optional marker color for invalid states. Default is
 * <mxConstants.DEFAULT_INVALID_COLOR>.
 * hotspot - Portion of the width and hight where a state intersects a
 * given coordinate pair. A value of 0 means always highlight. Default is
 * <mxConstants.DEFAULT_HOTSPOT>.
 */
function mxCellMarker(graph, validColor, invalidColor, hotspot)
{
\tmxEventSource.call(this);
\t
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.validColor = (validColor != null) ? validColor : mxConstants.DEFAULT_VALID_COLOR;
\t\tthis.invalidColor = (invalidColor != null) ? invalidColor : mxConstants.DEFAULT_INVALID_COLOR;
\t\tthis.hotspot = (hotspot != null) ? hotspot : mxConstants.DEFAULT_HOTSPOT;
\t\t
\t\tthis.highlight = new mxCellHighlight(graph);
\t}
};

/**
 * Extends mxEventSource.
 */
mxUtils.extend(mxCellMarker, mxEventSource);

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxCellMarker.prototype.graph = null;

/**
 * Variable: enabled
 * 
 * Specifies if the marker is enabled. Default is true.
 */
mxCellMarker.prototype.enabled = true;

/**
 * Variable: hotspot
 * 
 * Specifies the portion of the width and height that should trigger
 * a highlight. The area around the center of the cell to be marked is used
 * as the hotspot. Possible values are between 0 and 1. Default is
 * mxConstants.DEFAULT_HOTSPOT.
 */
mxCellMarker.prototype.hotspot = mxConstants.DEFAULT_HOTSPOT; 

/**
 * Variable: hotspotEnabled
 * 
 * Specifies if the hotspot is enabled. Default is false.
 */
mxCellMarker.prototype.hotspotEnabled = false;

/**
 * Variable: validColor
 * 
 * Holds the valid marker color.
 */
mxCellMarker.prototype.validColor = null;

/**
 * Variable: invalidColor
 * 
 * Holds the invalid marker color.
 */
mxCellMarker.prototype.invalidColor = null;

/**
 * Variable: currentColor
 * 
 * Holds the current marker color.
 */
mxCellMarker.prototype.currentColor = null;

/**
 * Variable: validState
 * 
 * Holds the marked <mxCellState> if it is valid.
 */
mxCellMarker.prototype.validState = null; 

/**
 * Variable: markedState
 * 
 * Holds the marked <mxCellState>.
 */
mxCellMarker.prototype.markedState = null;

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxCellMarker.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxCellMarker.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setHotspot
 * 
 * Sets the <hotspot>.
 */
mxCellMarker.prototype.setHotspot = function(hotspot)
{
\tthis.hotspot = hotspot;
};

/**
 * Function: getHotspot
 * 
 * Returns the <hotspot>.
 */
mxCellMarker.prototype.getHotspot = function()
{
\treturn this.hotspot;
};

/**
 * Function: setHotspotEnabled
 * 
 * Specifies whether the hotspot should be used in <intersects>.
 */
mxCellMarker.prototype.setHotspotEnabled = function(enabled)
{
\tthis.hotspotEnabled = enabled;
};

/**
 * Function: isHotspotEnabled
 * 
 * Returns true if hotspot is used in <intersects>.
 */
mxCellMarker.prototype.isHotspotEnabled = function()
{
\treturn this.hotspotEnabled;
};

/**
 * Function: hasValidState
 * 
 * Returns true if <validState> is not null.
 */
mxCellMarker.prototype.hasValidState = function()
{
\treturn this.validState != null;
};

/**
 * Function: getValidState
 * 
 * Returns the <validState>.
 */
mxCellMarker.prototype.getValidState = function()
{
\treturn this.validState;
};

/**
 * Function: getMarkedState
 * 
 * Returns the <markedState>.
 */
mxCellMarker.prototype.getMarkedState = function()
{
\treturn this.markedState;
};

/**
 * Function: reset
 * 
 * Resets the state of the cell marker.
 */
mxCellMarker.prototype.reset = function()
{
\tthis.validState = null;
\t
\tif (this.markedState != null)
\t{
\t\tthis.markedState = null;
\t\tthis.unmark();
\t}
};

/**
 * Function: process
 * 
 * Processes the given event and cell and marks the state returned by
 * <getState> with the color returned by <getMarkerColor>. If the
 * markerColor is not null, then the state is stored in <markedState>. If
 * <isValidState> returns true, then the state is stored in <validState>
 * regardless of the marker color. The state is returned regardless of the
 * marker color and valid state. 
 */
mxCellMarker.prototype.process = function(me)
{
\tvar state = null;
\t
\tif (this.isEnabled())
\t{
\t\tstate = this.getState(me);
\t\tthis.setCurrentState(state, me);
\t}
\t
\treturn state;
};

/**
 * Function: setCurrentState
 * 
 * Sets and marks the current valid state.
 */
mxCellMarker.prototype.setCurrentState = function(state, me, color)
{
\tvar isValid = (state != null) ? this.isValidState(state) : false;
\tcolor = (color != null) ? color : this.getMarkerColor(me.getEvent(), state, isValid);
\t
\tif (isValid)
\t{
\t\tthis.validState = state;
\t}
\telse
\t{
\t\tthis.validState = null;
\t}
\t
\tif (state != this.markedState || color != this.currentColor)
\t{
\t\tthis.currentColor = color;
\t\t
\t\tif (state != null && this.currentColor != null)
\t\t{
\t\t\tthis.markedState = state;
\t\t\tthis.mark();\t\t
\t\t}
\t\telse if (this.markedState != null)
\t\t{
\t\t\tthis.markedState = null;
\t\t\tthis.unmark();
\t\t}
\t}
};

/**
 * Function: markCell
 * 
 * Marks the given cell using the given color, or <validColor> if no color is specified.
 */
mxCellMarker.prototype.markCell = function(cell, color)
{
\tvar state = this.graph.getView().getState(cell);
\t
\tif (state != null)
\t{
\t\tthis.currentColor = (color != null) ? color : this.validColor;
\t\tthis.markedState = state;
\t\tthis.mark();
\t}
};

/**
 * Function: mark
 * 
 * Marks the <markedState> and fires a <mark> event.
 */
mxCellMarker.prototype.mark = function()
{
\tthis.highlight.setHighlightColor(this.currentColor);
\tthis.highlight.highlight(this.markedState);
\tthis.fireEvent(new mxEventObject(mxEvent.MARK, 'state', this.markedState));
};

/**
 * Function: unmark
 * 
 * Hides the marker and fires a <mark> event.
 */
mxCellMarker.prototype.unmark = function()
{
\tthis.mark();
};

/**
 * Function: isValidState
 * 
 * Returns true if the given <mxCellState> is a valid state. If this
 * returns true, then the state is stored in <validState>. The return value
 * of this method is used as the argument for <getMarkerColor>.
 */
mxCellMarker.prototype.isValidState = function(state)
{
\treturn true;
};

/**
 * Function: getMarkerColor
 * 
 * Returns the valid- or invalidColor depending on the value of isValid.
 * The given <mxCellState> is ignored by this implementation.
 */
mxCellMarker.prototype.getMarkerColor = function(evt, state, isValid)
{
\treturn (isValid) ? this.validColor : this.invalidColor;
};

/**
 * Function: getState
 * 
 * Uses <getCell>, <getStateToMark> and <intersects> to return the
 * <mxCellState> for the given <mxMouseEvent>.
 */
mxCellMarker.prototype.getState = function(me)
{
\tvar view = this.graph.getView();
\tvar cell = this.getCell(me);
\tvar state = this.getStateToMark(view.getState(cell));

\treturn (state != null && this.intersects(state, me)) ? state : null;
};

/**
 * Function: getCell
 * 
 * Returns the <mxCell> for the given event and cell. This returns the
 * given cell.
 */
mxCellMarker.prototype.getCell = function(me)
{
\treturn me.getCell();
};

/**
 * Function: getStateToMark
 * 
 * Returns the <mxCellState> to be marked for the given <mxCellState> under
 * the mouse. This returns the given state.
 */
mxCellMarker.prototype.getStateToMark = function(state)
{
\treturn state;
};

/**
 * Function: intersects
 * 
 * Returns true if the given coordinate pair intersects the given state.
 * This returns true if the <hotspot> is 0 or the coordinates are inside
 * the hotspot for the given cell state.
 */
mxCellMarker.prototype.intersects = function(state, me)
{
\tif (this.hotspotEnabled)
\t{
\t\treturn mxUtils.intersectsHotspot(state, me.getGraphX(), me.getGraphY(),
\t\t\tthis.hotspot, mxConstants.MIN_HOTSPOT_SIZE,
\t\t\tmxConstants.MAX_HOTSPOT_SIZE);
\t}
\t
\treturn true;
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxCellMarker.prototype.destroy = function()
{
\tthis.graph.getView().removeListener(this.resetHandler);
\tthis.graph.getModel().removeListener(this.resetHandler);
\tthis.highlight.destroy();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxSelectionCellsHandler
 * 
 * An event handler that manages cell handlers and invokes their mouse event
 * processing functions.
 * 
 * Group: Events
 * 
 * Event: mxEvent.ADD
 * 
 * Fires if a cell has been added to the selection. The <code>state</code>
 * property contains the <mxCellState> that has been added.
 * 
 * Event: mxEvent.REMOVE
 * 
 * Fires if a cell has been remove from the selection. The <code>state</code>
 * property contains the <mxCellState> that has been removed.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 */
function mxSelectionCellsHandler(graph)
{
\tmxEventSource.call(this);
\t
\tthis.graph = graph;
\tthis.handlers = new mxDictionary();
\tthis.graph.addMouseListener(this);
\t
\tthis.refreshHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.isEnabled())
\t\t{
\t\t\tthis.refresh();
\t\t}
\t});
\t
\tthis.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.refreshHandler);
\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler);
\tthis.graph.getView().addListener(mxEvent.SCALE, this.refreshHandler);
\tthis.graph.getView().addListener(mxEvent.TRANSLATE, this.refreshHandler);
\tthis.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.refreshHandler);
\tthis.graph.getView().addListener(mxEvent.DOWN, this.refreshHandler);
\tthis.graph.getView().addListener(mxEvent.UP, this.refreshHandler);
};

/**
 * Extends mxEventSource.
 */
mxUtils.extend(mxSelectionCellsHandler, mxEventSource);

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxSelectionCellsHandler.prototype.graph = null;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxSelectionCellsHandler.prototype.enabled = true;

/**
 * Variable: refreshHandler
 * 
 * Keeps a reference to an event listener for later removal.
 */
mxSelectionCellsHandler.prototype.refreshHandler = null;

/**
 * Variable: maxHandlers
 * 
 * Defines the maximum number of handlers to paint individually. Default is 100.
 */
mxSelectionCellsHandler.prototype.maxHandlers = 100;

/**
 * Variable: handlers
 * 
 * <mxDictionary> that maps from cells to handlers.
 */
mxSelectionCellsHandler.prototype.handlers = null;

/**
 * Function: isEnabled
 * 
 * Returns <enabled>.
 */
mxSelectionCellsHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Sets <enabled>.
 */
mxSelectionCellsHandler.prototype.setEnabled = function(value)
{
\tthis.enabled = value;
};

/**
 * Function: getHandler
 * 
 * Returns the handler for the given cell.
 */
mxSelectionCellsHandler.prototype.getHandler = function(cell)
{
\treturn this.handlers.get(cell);
};

/**
 * Function: isHandled
 * 
 * Returns true if the given cell has a handler.
 */
mxSelectionCellsHandler.prototype.isHandled = function(cell)
{
\treturn this.getHandler(cell) != null;
};

/**
 * Function: reset
 * 
 * Resets all handlers.
 */
mxSelectionCellsHandler.prototype.reset = function()
{
\tthis.handlers.visit(function(key, handler)
\t{
\t\thandler.reset.apply(handler);
\t});
};

/**
 * Function: getHandledSelectionCells
 * 
 * Reloads or updates all handlers.
 */
mxSelectionCellsHandler.prototype.getHandledSelectionCells = function()
{
\treturn this.graph.getSelectionCells();
};

/**
 * Function: refresh
 * 
 * Reloads or updates all handlers.
 */
mxSelectionCellsHandler.prototype.refresh = function()
{
\t// Removes all existing handlers
\tvar oldHandlers = this.handlers;
\tthis.handlers = new mxDictionary();
\t
\t// Creates handles for all selection cells
\tvar tmp = mxUtils.sortCells(this.getHandledSelectionCells(), false);

\t// Destroys or updates old handlers
\tfor (var i = 0; i < tmp.length; i++)
\t{
\t\tvar state = this.graph.view.getState(tmp[i]);

\t\tif (state != null)
\t\t{
\t\t\tvar handler = oldHandlers.remove(tmp[i]);

\t\t\tif (handler != null)
\t\t\t{
\t\t\t\tif (handler.state != state)
\t\t\t\t{
\t\t\t\t\thandler.destroy();
\t\t\t\t\thandler = null;
\t\t\t\t}
\t\t\t\telse if (!this.isHandlerActive(handler))
\t\t\t\t{
\t\t\t\t\tif (handler.refresh != null)
\t\t\t\t\t{
\t\t\t\t\t\thandler.refresh();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\thandler.redraw();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (handler != null)
\t\t\t{
\t\t\t\tthis.handlers.put(tmp[i], handler);
\t\t\t}
\t\t}
\t}
\t
\t// Destroys unused handlers
\toldHandlers.visit(mxUtils.bind(this, function(key, handler)
\t{
\t\tthis.fireEvent(new mxEventObject(mxEvent.REMOVE, 'state', handler.state));
\t\thandler.destroy();
\t}));
\t
\t// Creates new handlers and updates parent highlight on existing handlers
\tfor (var i = 0; i < tmp.length; i++)
\t{
\t\tvar state = this.graph.view.getState(tmp[i]);

\t\tif (state != null)
\t\t{
\t\t\tvar handler = this.handlers.get(tmp[i]);

\t\t\tif (handler == null)
\t\t\t{
\t\t\t\thandler = this.graph.createHandler(state);
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.ADD, 'state', state));
\t\t\t\tthis.handlers.put(tmp[i], handler);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\thandler.updateParentHighlight();
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isHandlerActive
 * 
 * Returns true if the given handler is active and should not be redrawn.
 */
mxSelectionCellsHandler.prototype.isHandlerActive = function(handler)
{
\treturn handler.index != null;
};

/**
 * Function: updateHandler
 * 
 * Updates the handler for the given shape if one exists.
 */
mxSelectionCellsHandler.prototype.updateHandler = function(state)
{
\tvar handler = this.handlers.remove(state.cell);
\t
\tif (handler != null)
\t{
\t\t// Transfers the current state to the new handler
\t\tvar index = handler.index;
\t\tvar x = handler.startX;
\t\tvar y = handler.startY;
\t\t
\t\thandler.destroy();
\t\thandler = this.graph.createHandler(state);

\t\tif (handler != null)
\t\t{
\t\t\tthis.handlers.put(state.cell, handler);
\t\t\t
\t\t\tif (index != null && x != null && y != null)
\t\t\t{
\t\t\t\thandler.start(x, y, index);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: mouseDown
 * 
 * Redirects the given event to the handlers.
 */
mxSelectionCellsHandler.prototype.mouseDown = function(sender, me)
{
\tif (this.graph.isEnabled() && this.isEnabled())
\t{
\t\tvar args = [sender, me];

\t\tthis.handlers.visit(function(key, handler)
\t\t{
\t\t\thandler.mouseDown.apply(handler, args);
\t\t});
\t}
};

/**
 * Function: mouseMove
 * 
 * Redirects the given event to the handlers.
 */
mxSelectionCellsHandler.prototype.mouseMove = function(sender, me)
{
\tif (this.graph.isEnabled() && this.isEnabled())
\t{
\t\tvar args = [sender, me];

\t\tthis.handlers.visit(function(key, handler)
\t\t{
\t\t\thandler.mouseMove.apply(handler, args);
\t\t});
\t}
};

/**
 * Function: mouseUp
 * 
 * Redirects the given event to the handlers.
 */
mxSelectionCellsHandler.prototype.mouseUp = function(sender, me)
{
\tif (this.graph.isEnabled() && this.isEnabled())
\t{
\t\tvar args = [sender, me];

\t\tthis.handlers.visit(function(key, handler)
\t\t{
\t\t\thandler.mouseUp.apply(handler, args);
\t\t});
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxSelectionCellsHandler.prototype.destroy = function()
{
\tthis.graph.removeMouseListener(this);
\t
\tif (this.refreshHandler != null)
\t{
\t\tthis.graph.getSelectionModel().removeListener(this.refreshHandler);
\t\tthis.graph.getModel().removeListener(this.refreshHandler);
\t\tthis.graph.getView().removeListener(this.refreshHandler);
\t\tthis.refreshHandler = null;
\t}
};
/**
 * Copyright (c) 2006-2016, JGraph Ltd
 * Copyright (c) 2006-2016, Gaudenz Alder
 */
/**
 * Class: mxConnectionHandler
 *
 * Graph event handler that creates new connections. Uses <mxTerminalMarker>
 * for finding and highlighting the source and target vertices and
 * <factoryMethod> to create the edge instance. This handler is built-into
 * <mxGraph.connectionHandler> and enabled using <mxGraph.setConnectable>.
 *
 * Example:
 * 
 * (code)
 * new mxConnectionHandler(graph, function(source, target, style)
 * {
 *   edge = new mxCell('', new mxGeometry());
 *   edge.setEdge(true);
 *   edge.setStyle(style);
 *   edge.geometry.relative = true;
 *   return edge;
 * });
 * (end)
 * 
 * Here is an alternative solution that just sets a specific user object for
 * new edges by overriding <insertEdge>.
 *
 * (code)
 * mxConnectionHandlerInsertEdge = mxConnectionHandler.prototype.insertEdge;
 * mxConnectionHandler.prototype.insertEdge = function(parent, id, value, source, target, style)
 * {
 *   value = 'Test';
 * 
 *   return mxConnectionHandlerInsertEdge.apply(this, arguments);
 * };
 * (end)
 * 
 * Using images to trigger connections:
 * 
 * This handler uses mxTerminalMarker to find the source and target cell for
 * the new connection and creates a new edge using <connect>. The new edge is
 * created using <createEdge> which in turn uses <factoryMethod> or creates a
 * new default edge.
 * 
 * The handler uses a \"highlight-paradigm\" for indicating if a cell is being
 * used as a source or target terminal, as seen in other diagramming products.
 * In order to allow both, moving and connecting cells at the same time,
 * <mxConstants.DEFAULT_HOTSPOT> is used in the handler to determine the hotspot
 * of a cell, that is, the region of the cell which is used to trigger a new
 * connection. The constant is a value between 0 and 1 that specifies the
 * amount of the width and height around the center to be used for the hotspot
 * of a cell and its default value is 0.5. In addition,
 * <mxConstants.MIN_HOTSPOT_SIZE> defines the minimum number of pixels for the
 * width and height of the hotspot.
 * 
 * This solution, while standards compliant, may be somewhat confusing because
 * there is no visual indicator for the hotspot and the highlight is seen to
 * switch on and off while the mouse is being moved in and out. Furthermore,
 * this paradigm does not allow to create different connections depending on
 * the highlighted hotspot as there is only one hotspot per cell and it
 * normally does not allow cells to be moved and connected at the same time as
 * there is no clear indication of the connectable area of the cell.
 * 
 * To come across these issues, the handle has an additional <createIcons> hook
 * with a default implementation that allows to create one icon to be used to
 * trigger new connections. If this icon is specified, then new connections can
 * only be created if the image is clicked while the cell is being highlighted.
 * The <createIcons> hook may be overridden to create more than one
 * <mxImageShape> for creating new connections, but the default implementation
 * supports one image and is used as follows:
 * 
 * In order to display the \"connect image\" whenever the mouse is over the cell,
 * an DEFAULT_HOTSPOT of 1 should be used:
 * 
 * (code)
 * mxConstants.DEFAULT_HOTSPOT = 1;
 * (end)
 * 
 * In order to avoid confusion with the highlighting, the highlight color
 * should not be used with a connect image:
 * 
 * (code)
 * mxConstants.HIGHLIGHT_COLOR = null;
 * (end)
 * 
 * To install the image, the connectImage field of the mxConnectionHandler must
 * be assigned a new <mxImage> instance:
 * 
 * (code)
 * mxConnectionHandler.prototype.connectImage = new mxImage('images/green-dot.gif', 14, 14);
 * (end)
 * 
 * This will use the green-dot.gif with a width and height of 14 pixels as the
 * image to trigger new connections. In createIcons the icon field of the
 * handler will be set in order to remember the icon that has been clicked for
 * creating the new connection. This field will be available under selectedIcon
 * in the connect method, which may be overridden to take the icon that
 * triggered the new connection into account. This is useful if more than one
 * icon may be used to create a connection.
 *
 * Group: Events
 * 
 * Event: mxEvent.START
 * 
 * Fires when a new connection is being created by the user. The <code>state</code>
 * property contains the state of the source cell.
 * 
 * Event: mxEvent.CONNECT
 * 
 * Fires between begin- and endUpdate in <connect>. The <code>cell</code>
 * property contains the inserted edge, the <code>event</code> and <code>target</code> 
 * properties contain the respective arguments that were passed to <connect> (where
 * target corresponds to the dropTarget argument). Finally, the <code>terminal</code>
 * property corresponds to the target argument in <connect> or the clone of the source
 * terminal if <createTarget> is enabled.
 * 
 * Note that the target is the cell under the mouse where the mouse button was released.
 * Depending on the logic in the handler, this doesn't necessarily have to be the target
 * of the inserted edge. To print the source, target or any optional ports IDs that the
 * edge is connected to, the following code can be used. To get more details about the
 * actual connection point, <mxGraph.getConnectionConstraint> can be used. To resolve
 * the port IDs, use <mxGraphModel.getCell>.
 * 
 * (code)
 * graph.connectionHandler.addListener(mxEvent.CONNECT, function(sender, evt)
 * {
 *   var edge = evt.getProperty('cell');
 *   var source = graph.getModel().getTerminal(edge, true);
 *   var target = graph.getModel().getTerminal(edge, false);
 *   
 *   var style = graph.getCellStyle(edge);
 *   var sourcePortId = style[mxConstants.STYLE_SOURCE_PORT];
 *   var targetPortId = style[mxConstants.STYLE_TARGET_PORT];
 *   
 *   mxLog.show();
 *   mxLog.debug('connect', edge, source.id, target.id, sourcePortId, targetPortId);
 * });
 * (end)
 *
 * Event: mxEvent.RESET
 * 
 * Fires when the <reset> method is invoked.
 *
 * Constructor: mxConnectionHandler
 *
 * Constructs an event handler that connects vertices using the specified
 * factory method to create the new edges. Modify
 * <mxConstants.ACTIVE_REGION> to setup the region on a cell which triggers
 * the creation of a new connection or use connect icons as explained
 * above.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * factoryMethod - Optional function to create the edge. The function takes
 * the source and target <mxCell> as the first and second argument and an
 * optional cell style from the preview as the third argument. It returns
 * the <mxCell> that represents the new edge.
 */
function mxConnectionHandler(graph, factoryMethod)
{
\tmxEventSource.call(this);
\t
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.factoryMethod = factoryMethod;
\t\tthis.init();
\t\t
\t\t// Handles escape keystrokes
\t\tthis.escapeHandler = mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tthis.reset();
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
\t}
};

/**
 * Extends mxEventSource.
 */
mxUtils.extend(mxConnectionHandler, mxEventSource);

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxConnectionHandler.prototype.graph = null;

/**
 * Variable: factoryMethod
 * 
 * Function that is used for creating new edges. The function takes the
 * source and target <mxCell> as the first and second argument and returns
 * a new <mxCell> that represents the edge. This is used in <createEdge>.
 */
mxConnectionHandler.prototype.factoryMethod = true;

/**
 * Variable: moveIconFront
 * 
 * Specifies if icons should be displayed inside the graph container instead
 * of the overlay pane. This is used for HTML labels on vertices which hide
 * the connect icon. This has precendence over <moveIconBack> when set
 * to true. Default is false.
 */
mxConnectionHandler.prototype.moveIconFront = false;

/**
 * Variable: moveIconBack
 * 
 * Specifies if icons should be moved to the back of the overlay pane. This can
 * be set to true if the icons of the connection handler conflict with other
 * handles, such as the vertex label move handle. Default is false.
 */
mxConnectionHandler.prototype.moveIconBack = false;

/**
 * Variable: connectImage
 * 
 * <mxImage> that is used to trigger the creation of a new connection. This
 * is used in <createIcons>. Default is null.
 */
mxConnectionHandler.prototype.connectImage = null;

/**
 * Variable: targetConnectImage
 * 
 * Specifies if the connect icon should be centered on the target state
 * while connections are being previewed. Default is false.
 */
mxConnectionHandler.prototype.targetConnectImage = false;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxConnectionHandler.prototype.enabled = true;

/**
 * Variable: select
 * 
 * Specifies if new edges should be selected. Default is true.
 */
mxConnectionHandler.prototype.select = true;

/**
 * Variable: createTarget
 * 
 * Specifies if <createTargetVertex> should be called if no target was under the
 * mouse for the new connection. Setting this to true means the connection
 * will be drawn as valid if no target is under the mouse, and
 * <createTargetVertex> will be called before the connection is created between
 * the source cell and the newly created vertex in <createTargetVertex>, which
 * can be overridden to create a new target. Default is false.
 */
mxConnectionHandler.prototype.createTarget = false;

/**
 * Variable: marker
 * 
 * Holds the <mxTerminalMarker> used for finding source and target cells.
 */
mxConnectionHandler.prototype.marker = null;

/**
 * Variable: constraintHandler
 * 
 * Holds the <mxConstraintHandler> used for drawing and highlighting
 * constraints.
 */
mxConnectionHandler.prototype.constraintHandler = null;

/**
 * Variable: error
 * 
 * Holds the current validation error while connections are being created.
 */
mxConnectionHandler.prototype.error = null;

/**
 * Variable: waypointsEnabled
 * 
 * Specifies if single clicks should add waypoints on the new edge. Default is
 * false.
 */
mxConnectionHandler.prototype.waypointsEnabled = false;

/**
 * Variable: ignoreMouseDown
 * 
 * Specifies if the connection handler should ignore the state of the mouse
 * button when highlighting the source. Default is false, that is, the
 * handler only highlights the source if no button is being pressed.
 */
mxConnectionHandler.prototype.ignoreMouseDown = false;

/**
 * Variable: first
 * 
 * Holds the <mxPoint> where the mouseDown took place while the handler is
 * active.
 */
mxConnectionHandler.prototype.first = null;

/**
 * Variable: connectIconOffset
 * 
 * Holds the offset for connect icons during connection preview.
 * Default is mxPoint(0, <mxConstants.TOOLTIP_VERTICAL_OFFSET>).
 * Note that placing the icon under the mouse pointer with an
 * offset of (0,0) will affect hit detection.
 */
mxConnectionHandler.prototype.connectIconOffset = new mxPoint(0, mxConstants.TOOLTIP_VERTICAL_OFFSET);

/**
 * Variable: edgeState
 * 
 * Optional <mxCellState> that represents the preview edge while the
 * handler is active. This is created in <createEdgeState>.
 */
mxConnectionHandler.prototype.edgeState = null;

/**
 * Variable: changeHandler
 * 
 * Holds the change event listener for later removal.
 */
mxConnectionHandler.prototype.changeHandler = null;

/**
 * Variable: drillHandler
 * 
 * Holds the drill event listener for later removal.
 */
mxConnectionHandler.prototype.drillHandler = null;

/**
 * Variable: mouseDownCounter
 * 
 * Counts the number of mouseDown events since the start. The initial mouse
 * down event counts as 1.
 */
mxConnectionHandler.prototype.mouseDownCounter = 0;

/**
 * Variable: movePreviewAway
 * 
 * Switch to enable moving the preview away from the mousepointer. This is required in browsers
 * where the preview cannot be made transparent to events and if the built-in hit detection on
 * the HTML elements in the page should be used. Default is the value of <mxClient.IS_VML>.
 */
mxConnectionHandler.prototype.movePreviewAway = mxClient.IS_VML;

/**
 * Variable: outlineConnect
 * 
 * Specifies if connections to the outline of a highlighted target should be
 * enabled. This will allow to place the connection point along the outline of
 * the highlighted target. Default is false.
 */
mxConnectionHandler.prototype.outlineConnect = false;

/**
 * Variable: livePreview
 * 
 * Specifies if the actual shape of the edge state should be used for the preview.
 * Default is false. (Ignored if no edge state is created in <createEdgeState>.)
 */
mxConnectionHandler.prototype.livePreview = false;

/**
 * Variable: cursor
 * 
 * Specifies the cursor to be used while the handler is active. Default is null.
 */
mxConnectionHandler.prototype.cursor = null;

/**
 * Variable: insertBeforeSource
 * 
 * Specifies if new edges should be inserted before the source vertex in the
 * cell hierarchy. Default is false for backwards compatibility.
 */
mxConnectionHandler.prototype.insertBeforeSource = false;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxConnectionHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};
\t
/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxConnectionHandler.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isInsertBefore
 * 
 * Returns <insertBeforeSource> for non-loops and false for loops.
 *
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to be inserted.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 * evt - Mousedown event of the connect gesture.
 * dropTarget - <mxCell> that represents the cell under the mouse when it was
 * released.
 */
mxConnectionHandler.prototype.isInsertBefore = function(edge, source, target, evt, dropTarget)
{
\treturn this.insertBeforeSource && source != target;
};

/**
 * Function: isCreateTarget
 * 
 * Returns <createTarget>.
 *
 * Parameters:
 *
 * evt - Current active native pointer event.
 */
mxConnectionHandler.prototype.isCreateTarget = function(evt)
{
\treturn this.createTarget;
};

/**
 * Function: setCreateTarget
 * 
 * Sets <createTarget>.
 */
mxConnectionHandler.prototype.setCreateTarget = function(value)
{
\tthis.createTarget = value;
};

/**
 * Function: createShape
 * 
 * Creates the preview shape for new connections.
 */
mxConnectionHandler.prototype.createShape = function()
{
\t// Creates the edge preview
\tvar shape = (this.livePreview && this.edgeState != null) ?
\t\tthis.graph.cellRenderer.createShape(this.edgeState) :
\t\tnew mxPolyline([], mxConstants.INVALID_COLOR);
\tshape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\tmxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\tshape.scale = this.graph.view.scale;
\tshape.pointerEvents = false;
\tshape.isDashed = true;
\tshape.init(this.graph.getView().getOverlayPane());
\tmxEvent.redirectMouseEvents(shape.node, this.graph, null);

\treturn shape;
};

/**
 * Function: init
 * 
 * Initializes the shapes required for this connection handler. This should
 * be invoked if <mxGraph.container> is assigned after the connection
 * handler has been created.
 */
mxConnectionHandler.prototype.init = function()
{
\tthis.graph.addMouseListener(this);
\tthis.marker = this.createMarker();
\tthis.constraintHandler = new mxConstraintHandler(this.graph);

\t// Redraws the icons if the graph changes
\tthis.changeHandler = mxUtils.bind(this, function(sender)
\t{
\t\tif (this.iconState != null)
\t\t{
\t\t\tthis.iconState = this.graph.getView().getState(this.iconState.cell);
\t\t}
\t\t
\t\tif (this.iconState != null)
\t\t{
\t\t\tthis.redrawIcons(this.icons, this.iconState);
\t\t\tthis.constraintHandler.reset();
\t\t}
\t\telse if (this.previous != null && this.graph.view.getState(this.previous.cell) == null)
\t\t{
\t\t\tthis.reset();
\t\t}
\t});
\t
\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
\tthis.graph.getView().addListener(mxEvent.SCALE, this.changeHandler);
\tthis.graph.getView().addListener(mxEvent.TRANSLATE, this.changeHandler);
\tthis.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.changeHandler);
\t
\t// Removes the icon if we step into/up or start editing
\tthis.drillHandler = mxUtils.bind(this, function(sender)
\t{
\t\tthis.reset();
\t});
\t
\tthis.graph.addListener(mxEvent.START_EDITING, this.drillHandler);
\tthis.graph.getView().addListener(mxEvent.DOWN, this.drillHandler);
\tthis.graph.getView().addListener(mxEvent.UP, this.drillHandler);
};

/**
 * Function: isConnectableCell
 * 
 * Returns true if the given cell is connectable. This is a hook to
 * disable floating connections. This implementation returns true.
 */
mxConnectionHandler.prototype.isConnectableCell = function(cell)
{
\treturn true;
};

/**
 * Function: createMarker
 * 
 * Creates and returns the <mxCellMarker> used in <marker>.
 */
mxConnectionHandler.prototype.createMarker = function()
{
\tvar marker = new mxCellMarker(this.graph);
\tmarker.hotspotEnabled = true;

\t// Overrides to return cell at location only if valid (so that
\t// there is no highlight for invalid cells)
\tmarker.getCell = mxUtils.bind(this, function(me)
\t{
\t\tvar cell = mxCellMarker.prototype.getCell.apply(marker, arguments);
\t\tthis.error = null;
\t\t
\t\t// Checks for cell at preview point (with grid)
\t\tif (cell == null && this.currentPoint != null)
\t\t{
\t\t\tcell = this.graph.getCellAt(this.currentPoint.x, this.currentPoint.y);
\t\t}
\t\t
\t\t// Uses connectable parent vertex if one exists
\t\tif (cell != null && !this.graph.isCellConnectable(cell))
\t\t{
\t\t\tvar parent = this.graph.getModel().getParent(cell);
\t\t\t
\t\t\tif (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
\t\t\t{
\t\t\t\tcell = parent;
\t\t\t}
\t\t}
\t\t
\t\tif ((this.graph.isSwimlane(cell) && this.currentPoint != null &&
\t\t\tthis.graph.hitsSwimlaneContent(cell, this.currentPoint.x, this.currentPoint.y)) ||
\t\t\t!this.isConnectableCell(cell))
\t\t{
\t\t\tcell = null;
\t\t}
\t\t
\t\tif (cell != null)
\t\t{
\t\t\tif (this.isConnecting())
\t\t\t{
\t\t\t\tif (this.previous != null)
\t\t\t\t{
\t\t\t\t\tthis.error = this.validateConnection(this.previous.cell, cell);
\t\t\t\t\t
\t\t\t\t\tif (this.error != null && this.error.length == 0)
\t\t\t\t\t{
\t\t\t\t\t\tcell = null;
\t\t\t\t\t\t
\t\t\t\t\t\t// Enables create target inside groups
\t\t\t\t\t\tif (this.isCreateTarget(me.getEvent()))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.error = null;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (!this.isValidSource(cell, me))
\t\t\t{
\t\t\t\tcell = null;
\t\t\t}
\t\t}
\t\telse if (this.isConnecting() && !this.isCreateTarget(me.getEvent()) &&
\t\t\t\t!this.graph.allowDanglingEdges)
\t\t{
\t\t\tthis.error = '';
\t\t}

\t\treturn cell;
\t});

\t// Sets the highlight color according to validateConnection
\tmarker.isValidState = mxUtils.bind(this, function(state)
\t{
\t\tif (this.isConnecting())
\t\t{
\t\t\treturn this.error == null;
\t\t}
\t\telse
\t\t{
\t\t\treturn mxCellMarker.prototype.isValidState.apply(marker, arguments);
\t\t}
\t});

\t// Overrides to use marker color only in highlight mode or for
\t// target selection
\tmarker.getMarkerColor = mxUtils.bind(this, function(evt, state, isValid)
\t{
\t\treturn (this.connectImage == null || this.isConnecting()) ?
\t\t\tmxCellMarker.prototype.getMarkerColor.apply(marker, arguments) :
\t\t\tnull;
\t});

\t// Overrides to use hotspot only for source selection otherwise
\t// intersects always returns true when over a cell
\tmarker.intersects = mxUtils.bind(this, function(state, evt)
\t{
\t\tif (this.connectImage != null || this.isConnecting())
\t\t{
\t\t\treturn true;
\t\t}
\t\t
\t\treturn mxCellMarker.prototype.intersects.apply(marker, arguments);
\t});

\treturn marker;
};

/**
 * Function: start
 * 
 * Starts a new connection for the given state and coordinates.
 */
mxConnectionHandler.prototype.start = function(state, x, y, edgeState)
{
\tthis.previous = state;
\tthis.first = new mxPoint(x, y);
\tthis.edgeState = (edgeState != null) ? edgeState : this.createEdgeState(null);
\t
\t// Marks the source state
\tthis.marker.currentColor = this.marker.validColor;
\tthis.marker.markedState = state;
\tthis.marker.mark();

\tthis.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous));
};

/**
 * Function: isConnecting
 * 
 * Returns true if the source terminal has been clicked and a new
 * connection is currently being previewed.
 */
mxConnectionHandler.prototype.isConnecting = function()
{
\treturn this.first != null && this.shape != null;
};

/**
 * Function: isValidSource
 * 
 * Returns <mxGraph.isValidSource> for the given source terminal.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the source terminal.
 * me - <mxMouseEvent> that is associated with this call.
 */
mxConnectionHandler.prototype.isValidSource = function(cell, me)
{
\treturn this.graph.isValidSource(cell);
};

/**
 * Function: isValidTarget
 * 
 * Returns true. The call to <mxGraph.isValidTarget> is implicit by calling
 * <mxGraph.getEdgeValidationError> in <validateConnection>. This is an
 * additional hook for disabling certain targets in this specific handler.
 * 
 * Parameters:
 * 
 * cell - <mxCell> that represents the target terminal.
 */
mxConnectionHandler.prototype.isValidTarget = function(cell)
{
\treturn true;
};

/**
 * Function: validateConnection
 * 
 * Returns the error message or an empty string if the connection for the
 * given source target pair is not valid. Otherwise it returns null. This
 * implementation uses <mxGraph.getEdgeValidationError>.
 * 
 * Parameters:
 * 
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 */
mxConnectionHandler.prototype.validateConnection = function(source, target)
{
\tif (!this.isValidTarget(target))
\t{
\t\treturn '';
\t}
\t
\treturn this.graph.getEdgeValidationError(null, source, target);
};

/**
 * Function: getConnectImage
 * 
 * Hook to return the <mxImage> used for the connection icon of the given
 * <mxCellState>. This implementation returns <connectImage>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose connect image should be returned.
 */
mxConnectionHandler.prototype.getConnectImage = function(state)
{
\treturn this.connectImage;
};

/**
 * Function: isMoveIconToFrontForState
 * 
 * Returns true if the state has a HTML label in the graph's container, otherwise
 * it returns <moveIconFront>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose connect icons should be returned.
 */
mxConnectionHandler.prototype.isMoveIconToFrontForState = function(state)
{
\tif (state.text != null && state.text.node.parentNode == this.graph.container)
\t{
\t\treturn true;
\t}
\t
\treturn this.moveIconFront;
};

/**
 * Function: createIcons
 * 
 * Creates the array <mxImageShapes> that represent the connect icons for
 * the given <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> whose connect icons should be returned.
 */
mxConnectionHandler.prototype.createIcons = function(state)
{
\tvar image = this.getConnectImage(state);
\t
\tif (image != null && state != null)
\t{
\t\tthis.iconState = state;
\t\tvar icons = [];

\t\t// Cannot use HTML for the connect icons because the icon receives all
\t\t// mouse move events in IE, must use VML and SVG instead even if the
\t\t// connect-icon appears behind the selection border and the selection
\t\t// border consumes the events before the icon gets a chance
\t\tvar bounds = new mxRectangle(0, 0, image.width, image.height);
\t\tvar icon = new mxImageShape(bounds, image.src, null, null, 0);
\t\ticon.preserveImageAspect = false;
\t\t
\t\tif (this.isMoveIconToFrontForState(state))
\t\t{
\t\t\ticon.dialect = mxConstants.DIALECT_STRICTHTML;
\t\t\ticon.init(this.graph.container);
\t\t}
\t\telse
\t\t{
\t\t\ticon.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ?
\t\t\t\tmxConstants.DIALECT_SVG : mxConstants.DIALECT_VML;
\t\t\ticon.init(this.graph.getView().getOverlayPane());

\t\t\t// Move the icon back in the overlay pane
\t\t\tif (this.moveIconBack && icon.node.previousSibling != null)
\t\t\t{
\t\t\t\ticon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
\t\t\t}
\t\t}

\t\ticon.node.style.cursor = mxConstants.CURSOR_CONNECT;

\t\t// Events transparency
\t\tvar getState = mxUtils.bind(this, function()
\t\t{
\t\t\treturn (this.currentState != null) ? this.currentState : state;
\t\t});
\t\t
\t\t// Updates the local icon before firing the mouse down event.
\t\tvar mouseDown = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tif (!mxEvent.isConsumed(evt))
\t\t\t{
\t\t\t\tthis.icon = icon;
\t\t\t\tthis.graph.fireMouseEvent(mxEvent.MOUSE_DOWN,
\t\t\t\t\tnew mxMouseEvent(evt, getState()));
\t\t\t}
\t\t});

\t\tmxEvent.redirectMouseEvents(icon.node, this.graph, getState, mouseDown);
\t\t
\t\ticons.push(icon);
\t\tthis.redrawIcons(icons, this.iconState);
\t\t
\t\treturn icons;
\t}
\t
\treturn null;
};

/**
 * Function: redrawIcons
 * 
 * Redraws the given array of <mxImageShapes>.
 * 
 * Parameters:
 * 
 * icons - Optional array of <mxImageShapes> to be redrawn.
 */
mxConnectionHandler.prototype.redrawIcons = function(icons, state)
{
\tif (icons != null && icons[0] != null && state != null)
\t{
\t\tvar pos = this.getIconPosition(icons[0], state);
\t\ticons[0].bounds.x = pos.x;
\t\ticons[0].bounds.y = pos.y;
\t\ticons[0].redraw();
\t}
};

/**
 * Function: getIconPosition
 * 
 * Returns the center position of the given icon.
 * 
 * Parameters:
 * 
 * icon - The connect icon of <mxImageShape> with the mouse.
 * state - <mxCellState> under the mouse.
 */
mxConnectionHandler.prototype.getIconPosition = function(icon, state)
{
\tvar scale = this.graph.getView().scale;
\tvar cx = state.getCenterX();
\tvar cy = state.getCenterY();
\t
\tif (this.graph.isSwimlane(state.cell))
\t{
\t\tvar size = this.graph.getStartSize(state.cell);
\t\t
\t\tcx = (size.width != 0) ? state.x + size.width * scale / 2 : cx;
\t\tcy = (size.height != 0) ? state.y + size.height * scale / 2 : cy;
\t\t
\t\tvar alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
\t\t
\t\tif (alpha != 0)
\t\t{
\t\t\tvar cos = Math.cos(alpha);
\t\t\tvar sin = Math.sin(alpha);
\t\t\tvar ct = new mxPoint(state.getCenterX(), state.getCenterY());
\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin, ct);
\t\t\tcx = pt.x;
\t\t\tcy = pt.y;
\t\t}
\t}

\treturn new mxPoint(cx - icon.bounds.width / 2,
\t\t\tcy - icon.bounds.height / 2);
};

/**
 * Function: destroyIcons
 * 
 * Destroys the connect icons and resets the respective state.
 */
mxConnectionHandler.prototype.destroyIcons = function()
{
\tif (this.icons != null)
\t{
\t\tfor (var i = 0; i < this.icons.length; i++)
\t\t{
\t\t\tthis.icons[i].destroy();
\t\t}
\t\t
\t\tthis.icons = null;
\t\tthis.icon = null;
\t\tthis.selectedIcon = null;
\t\tthis.iconState = null;
\t}
};

/**
 * Function: isStartEvent
 * 
 * Returns true if the given mouse down event should start this handler. The
 * This implementation returns true if the event does not force marquee
 * selection, and the currentConstraint and currentFocus of the
 * <constraintHandler> are not null, or <previous> and <error> are not null and
 * <icons> is null or <icons> and <icon> are not null.
 */
mxConnectionHandler.prototype.isStartEvent = function(me)
{
\treturn ((this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null) ||
\t\t(this.previous != null && this.error == null && (this.icons == null || (this.icons != null &&
\t\tthis.icon != null))));
};

/**
 * Function: mouseDown
 * 
 * Handles the event by initiating a new connection.
 */
mxConnectionHandler.prototype.mouseDown = function(sender, me)
{
\tthis.mouseDownCounter++;
\t
\tif (this.isEnabled() && this.graph.isEnabled() && !me.isConsumed() &&
\t\t!this.isConnecting() && this.isStartEvent(me))
\t{
\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\tthis.constraintHandler.currentFocus != null &&
\t\t\tthis.constraintHandler.currentPoint != null)
\t\t{
\t\t\tthis.sourceConstraint = this.constraintHandler.currentConstraint;
\t\t\tthis.previous = this.constraintHandler.currentFocus;
\t\t\tthis.first = this.constraintHandler.currentPoint.clone();
\t\t}
\t\telse
\t\t{
\t\t\t// Stores the location of the initial mousedown
\t\t\tthis.first = new mxPoint(me.getGraphX(), me.getGraphY());
\t\t}
\t
\t\tthis.edgeState = this.createEdgeState(me);
\t\tthis.mouseDownCounter = 1;
\t\t
\t\tif (this.waypointsEnabled && this.shape == null)
\t\t{
\t\t\tthis.waypoints = null;
\t\t\tthis.shape = this.createShape();
\t\t\t
\t\t\tif (this.edgeState != null)
\t\t\t{
\t\t\t\tthis.shape.apply(this.edgeState);
\t\t\t}
\t\t}

\t\t// Stores the starting point in the geometry of the preview
\t\tif (this.previous == null && this.edgeState != null)
\t\t{
\t\t\tvar pt = this.graph.getPointForEvent(me.getEvent());
\t\t\tthis.edgeState.cell.geometry.setTerminalPoint(pt, true);
\t\t}
\t\t
\t\tthis.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous));

\t\tme.consume();
\t}

\tthis.selectedIcon = this.icon;
\tthis.icon = null;
};

/**
 * Function: isImmediateConnectSource
 * 
 * Returns true if a tap on the given source state should immediately start
 * connecting. This implementation returns true if the state is not movable
 * in the graph. 
 */
mxConnectionHandler.prototype.isImmediateConnectSource = function(state)
{
\treturn !this.graph.isCellMovable(state.cell);
};

/**
 * Function: createEdgeState
 * 
 * Hook to return an <mxCellState> which may be used during the preview.
 * This implementation returns null.
 * 
 * Use the following code to create a preview for an existing edge style:
 * 
 * (code)
 * graph.connectionHandler.createEdgeState = function(me)
 * {
 *   var edge = graph.createEdge(null, null, null, null, null, 'edgeStyle=elbowEdgeStyle');
 *   
 *   return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));
 * };
 * (end)
 */
mxConnectionHandler.prototype.createEdgeState = function(me)
{
\treturn null;
};

/**
 * Function: isOutlineConnectEvent
 * 
 * Returns true if <outlineConnect> is true and the source of the event is the outline shape
 * or shift is pressed.
 */
mxConnectionHandler.prototype.isOutlineConnectEvent = function(me)
{
\tvar offset = mxUtils.getOffset(this.graph.container);
\tvar evt = me.getEvent();
\t
\tvar clientX = mxEvent.getClientX(evt);
\tvar clientY = mxEvent.getClientY(evt);
\t
\tvar doc = document.documentElement;
\tvar left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
\tvar top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
\t
\tvar gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
\tvar gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;

\treturn this.outlineConnect && !mxEvent.isShiftDown(me.getEvent()) &&
\t\t(me.isSource(this.marker.highlight.shape) ||
\t\t(mxEvent.isAltDown(me.getEvent()) && me.getState() != null) ||
\t\tthis.marker.highlight.isHighlightAt(clientX, clientY) ||
\t\t((gridX != clientX || gridY != clientY) && me.getState() == null &&
\t\tthis.marker.highlight.isHighlightAt(gridX, gridY)));
};

/**
 * Function: updateCurrentState
 * 
 * Updates the current state for a given mouse move event by using
 * the <marker>.
 */
mxConnectionHandler.prototype.updateCurrentState = function(me, point)
{
\tthis.constraintHandler.update(me, this.first == null, false, (this.first == null ||
\t\tme.isSource(this.marker.highlight.shape)) ? null : point);
\t
\tif (this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null)
\t{
\t\t// Handles special case where grid is large and connection point is at actual point in which
\t\t// case the outline is not followed as long as we're < gridSize / 2 away from that point
\t\tif (this.marker.highlight != null && this.marker.highlight.state != null &&
\t\t\tthis.marker.highlight.state.cell == this.constraintHandler.currentFocus.cell)
\t\t{
\t\t\t// Direct repaint needed if cell already highlighted
\t\t\tif (this.marker.highlight.shape.stroke != 'transparent')
\t\t\t{
\t\t\t\tthis.marker.highlight.shape.stroke = 'transparent';
\t\t\t\tthis.marker.highlight.repaint();
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tthis.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
\t\t}

\t\t// Updates validation state
\t\tif (this.previous != null)
\t\t{
\t\t\tthis.error = this.validateConnection(this.previous.cell, this.constraintHandler.currentFocus.cell);
\t\t\t
\t\t\tif (this.error == null)
\t\t\t{
\t\t\t\tthis.currentState = this.constraintHandler.currentFocus;
\t\t\t}
\t\t\t\t\t
\t\t\tif (this.error != null || (this.currentState != null &&
\t\t\t\t!this.isCellEnabled(this.currentState.cell)))
\t\t\t{
\t\t\t\tthis.constraintHandler.reset();
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tif (this.graph.isIgnoreTerminalEvent(me.getEvent()))
\t\t{
\t\t\tthis.marker.reset();
\t\t\tthis.currentState = null;
\t\t}
\t\telse
\t\t{
\t\t\tthis.marker.process(me);
\t\t\tthis.currentState = this.marker.getValidState();
\t\t}
\t\t\t
\t\tif (this.currentState != null && !this.isCellEnabled(this.currentState.cell))
\t\t{
\t\t\tthis.constraintHandler.reset();
\t\t\tthis.marker.reset();
\t\t\tthis.currentState = null;
\t\t}

\t\tvar outline = this.isOutlineConnectEvent(me);
\t\t
\t\tif (this.currentState != null && outline)
\t\t{
\t\t\t// Handles special case where mouse is on outline away from actual end point
\t\t\t// in which case the grid is ignored and mouse point is used instead
\t\t\tif (me.isSource(this.marker.highlight.shape))
\t\t\t{
\t\t\t\tpoint = new mxPoint(me.getGraphX(), me.getGraphY());
\t\t\t}
\t\t\t
\t\t\tvar constraint = this.graph.getOutlineConstraint(point, this.currentState, me);
\t\t\tthis.constraintHandler.setFocus(me, this.currentState, false);
\t\t\tthis.constraintHandler.currentConstraint = constraint;
\t\t\tthis.constraintHandler.currentPoint = point;
\t\t}

\t\tif (this.outlineConnect)
\t\t{
\t\t\tif (this.marker.highlight != null && this.marker.highlight.shape != null)
\t\t\t{
\t\t\t\tvar s = this.graph.view.scale;
\t\t\t\t
\t\t\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\t\t\tthis.constraintHandler.currentFocus != null)
\t\t\t\t{
\t\t\t\t\tthis.marker.highlight.shape.stroke = mxConstants.OUTLINE_HIGHLIGHT_COLOR;
\t\t\t\t\tthis.marker.highlight.shape.strokewidth = mxConstants.OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
\t\t\t\t\tthis.marker.highlight.repaint();
\t\t\t\t} 
\t\t\t\telse if (this.marker.hasValidState())
\t\t\t\t{
\t\t\t\t\t// Handles special case where actual end point of edge and current mouse point
\t\t\t\t\t// are not equal (due to grid snapping) and there is no hit on shape or highlight
\t\t\t\t\t// but ignores cases where parent is used for non-connectable child cells
\t\t\t\t\tif (this.graph.isCellConnectable(me.getCell()) &&
\t\t\t\t\t\tthis.marker.getValidState() != me.getState())
\t\t\t\t\t{
\t\t\t\t\t\tthis.marker.highlight.shape.stroke = 'transparent';
\t\t\t\t\t\tthis.currentState = null;
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tthis.marker.highlight.shape.stroke = mxConstants.DEFAULT_VALID_COLOR;
\t\t\t\t\t}
\t
\t\t\t\t\tthis.marker.highlight.shape.strokewidth = mxConstants.HIGHLIGHT_STROKEWIDTH / s / s;
\t\t\t\t\tthis.marker.highlight.repaint();
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isCellEnabled
 * 
 * Returns true if the given cell allows new connections to be created. This implementation
 * always returns true.
 */
mxConnectionHandler.prototype.isCellEnabled = function(cell)
{
\treturn true;
};

/**
 * Function: convertWaypoint
 * 
 * Converts the given point from screen coordinates to model coordinates.
 */
mxConnectionHandler.prototype.convertWaypoint = function(point)
{
\tvar scale = this.graph.getView().getScale();
\tvar tr = this.graph.getView().getTranslate();
\t
\tpoint.x = point.x / scale - tr.x;
\tpoint.y = point.y / scale - tr.y;
};

/**
 * Function: snapToPreview
 * 
 * Called to snap the given point to the current preview. This snaps to the
 * first point of the preview if alt is not pressed.
 */
mxConnectionHandler.prototype.snapToPreview = function(me, point)
{
\tif (!mxEvent.isAltDown(me.getEvent()) && this.previous != null)
\t{
\t\tvar tol = this.graph.gridSize * this.graph.view.scale / 2;\t
\t\tvar tmp = (this.sourceConstraint != null) ? this.first :
\t\t\tnew mxPoint(this.previous.getCenterX(), this.previous.getCenterY());

\t\tif (Math.abs(tmp.x - me.getGraphX()) < tol)
\t\t{
\t\t\tpoint.x = tmp.x;
\t\t}
\t\t
\t\tif (Math.abs(tmp.y - me.getGraphY()) < tol)
\t\t{
\t\t\tpoint.y = tmp.y;
\t\t}
\t}\t
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the preview edge or by highlighting
 * a possible source or target terminal.
 */
mxConnectionHandler.prototype.mouseMove = function(sender, me)
{
\tif (!me.isConsumed() && (this.ignoreMouseDown || this.first != null || !this.graph.isMouseDown))
\t{
\t\t// Handles special case when handler is disabled during highlight
\t\tif (!this.isEnabled() && this.currentState != null)
\t\t{
\t\t\tthis.destroyIcons();
\t\t\tthis.currentState = null;
\t\t}

\t\tvar view = this.graph.getView();
\t\tvar scale = view.scale;
\t\tvar tr = view.translate;
\t\tvar point = new mxPoint(me.getGraphX(), me.getGraphY());
\t\tthis.error = null;

\t\tif (this.graph.isGridEnabledEvent(me.getEvent()))
\t\t{
\t\t\tpoint = new mxPoint((this.graph.snap(point.x / scale - tr.x) + tr.x) * scale,
\t\t\t\t(this.graph.snap(point.y / scale - tr.y) + tr.y) * scale);
\t\t}
\t\t
\t\tthis.snapToPreview(me, point);
\t\tthis.currentPoint = point;
\t\t
\t\tif ((this.first != null || (this.isEnabled() && this.graph.isEnabled())) &&
\t\t\t(this.shape != null || this.first == null ||
\t\t\tMath.abs(me.getGraphX() - this.first.x) > this.graph.tolerance ||
\t\t\tMath.abs(me.getGraphY() - this.first.y) > this.graph.tolerance))
\t\t{
\t\t\tthis.updateCurrentState(me, point);
\t\t}

\t\tif (this.first != null)
\t\t{
\t\t\tvar constraint = null;
\t\t\tvar current = point;
\t\t\t
\t\t\t// Uses the current point from the constraint handler if available
\t\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\t\tthis.constraintHandler.currentFocus != null &&
\t\t\t\tthis.constraintHandler.currentPoint != null)
\t\t\t{
\t\t\t\tconstraint = this.constraintHandler.currentConstraint;
\t\t\t\tcurrent = this.constraintHandler.currentPoint.clone();
\t\t\t}
\t\t\telse if (this.previous != null && !this.graph.isIgnoreTerminalEvent(me.getEvent()) &&
\t\t\t\tmxEvent.isShiftDown(me.getEvent()))
\t\t\t{
\t\t\t\tif (Math.abs(this.previous.getCenterX() - point.x) <
\t\t\t\t\tMath.abs(this.previous.getCenterY() - point.y))
\t\t\t\t{
\t\t\t\t\tpoint.x = this.previous.getCenterX();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tpoint.y = this.previous.getCenterY();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar pt2 = this.first;
\t\t\t
\t\t\t// Moves the connect icon with the mouse
\t\t\tif (this.selectedIcon != null)
\t\t\t{
\t\t\t\tvar w = this.selectedIcon.bounds.width;
\t\t\t\tvar h = this.selectedIcon.bounds.height;
\t\t\t\t
\t\t\t\tif (this.currentState != null && this.targetConnectImage)
\t\t\t\t{
\t\t\t\t\tvar pos = this.getIconPosition(this.selectedIcon, this.currentState);
\t\t\t\t\tthis.selectedIcon.bounds.x = pos.x;
\t\t\t\t\tthis.selectedIcon.bounds.y = pos.y;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar bounds = new mxRectangle(me.getGraphX() + this.connectIconOffset.x,
\t\t\t\t\t\tme.getGraphY() + this.connectIconOffset.y, w, h);
\t\t\t\t\tthis.selectedIcon.bounds = bounds;
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.selectedIcon.redraw();
\t\t\t}

\t\t\t// Uses edge state to compute the terminal points
\t\t\tif (this.edgeState != null)
\t\t\t{
\t\t\t\tthis.updateEdgeState(current, constraint);
\t\t\t\tcurrent = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 1];
\t\t\t\tpt2 = this.edgeState.absolutePoints[0];
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (this.currentState != null)
\t\t\t\t{
\t\t\t\t\tif (this.constraintHandler.currentConstraint == null)
\t\t\t\t\t{
\t\t\t\t\t\tvar tmp = this.getTargetPerimeterPoint(this.currentState, me);
\t\t\t\t\t\t
\t\t\t\t\t\tif (tmp != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tcurrent = tmp;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Computes the source perimeter point
\t\t\t\tif (this.sourceConstraint == null && this.previous != null)
\t\t\t\t{
\t\t\t\t\tvar next = (this.waypoints != null && this.waypoints.length > 0) ?
\t\t\t\t\t\t\tthis.waypoints[0] : current;
\t\t\t\t\tvar tmp = this.getSourcePerimeterPoint(this.previous, next, me);
\t\t\t\t\t
\t\t\t\t\tif (tmp != null)
\t\t\t\t\t{
\t\t\t\t\t\tpt2 = tmp;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// Makes sure the cell under the mousepointer can be detected
\t\t\t// by moving the preview shape away from the mouse. This
\t\t\t// makes sure the preview shape does not prevent the detection
\t\t\t// of the cell under the mousepointer even for slow gestures.
\t\t\tif (this.currentState == null && this.movePreviewAway)
\t\t\t{
\t\t\t\tvar tmp = pt2; 
\t\t\t\t
\t\t\t\tif (this.edgeState != null && this.edgeState.absolutePoints.length >= 2)
\t\t\t\t{
\t\t\t\t\tvar tmp2 = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 2];
\t\t\t\t\t
\t\t\t\t\tif (tmp2 != null)
\t\t\t\t\t{
\t\t\t\t\t\ttmp = tmp2;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar dx = current.x - tmp.x;
\t\t\t\tvar dy = current.y - tmp.y;
\t\t\t\t
\t\t\t\tvar len = Math.sqrt(dx * dx + dy * dy);
\t\t\t\t
\t\t\t\tif (len == 0)
\t\t\t\t{
\t\t\t\t\treturn;
\t\t\t\t}

\t\t\t\t// Stores old point to reuse when creating edge
\t\t\t\tthis.originalPoint = current.clone();
\t\t\t\tcurrent.x -= dx * 4 / len;
\t\t\t\tcurrent.y -= dy * 4 / len;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.originalPoint = null;
\t\t\t}
\t\t\t
\t\t\t// Creates the preview shape (lazy)
\t\t\tif (this.shape == null)
\t\t\t{
\t\t\t\tvar dx = Math.abs(me.getGraphX() - this.first.x);
\t\t\t\tvar dy = Math.abs(me.getGraphY() - this.first.y);

\t\t\t\tif (dx > this.graph.tolerance || dy > this.graph.tolerance)
\t\t\t\t{
\t\t\t\t\tthis.shape = this.createShape();

\t\t\t\t\tif (this.edgeState != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.shape.apply(this.edgeState);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Revalidates current connection
\t\t\t\t\tthis.updateCurrentState(me, point);
\t\t\t\t}
\t\t\t}

\t\t\t// Updates the points in the preview edge
\t\t\tif (this.shape != null)
\t\t\t{
\t\t\t\tif (this.edgeState != null)
\t\t\t\t{
\t\t\t\t\tthis.shape.points = this.edgeState.absolutePoints;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar pts = [pt2];
\t\t\t\t\t
\t\t\t\t\tif (this.waypoints != null)
\t\t\t\t\t{
\t\t\t\t\t\tpts = pts.concat(this.waypoints);
\t\t\t\t\t}

\t\t\t\t\tpts.push(current);
\t\t\t\t\tthis.shape.points = pts;
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.drawPreview();
\t\t\t}
\t\t\t
\t\t\t// Makes sure endpoint of edge is visible during connect
\t\t\tif (this.cursor != null)
\t\t\t{
\t\t\t\tthis.graph.container.style.cursor = this.cursor;
\t\t\t}
\t\t\t
\t\t\tmxEvent.consume(me.getEvent());
\t\t\tme.consume();
\t\t}
\t\telse if (!this.isEnabled() || !this.graph.isEnabled())
\t\t{
\t\t\tthis.constraintHandler.reset();
\t\t}
\t\telse if (this.previous != this.currentState && this.edgeState == null)
\t\t{
\t\t\tthis.destroyIcons();
\t\t\t
\t\t\t// Sets the cursor on the current shape\t\t\t\t
\t\t\tif (this.currentState != null && this.error == null && this.constraintHandler.currentConstraint == null)
\t\t\t{
\t\t\t\tthis.icons = this.createIcons(this.currentState);

\t\t\t\tif (this.icons == null)
\t\t\t\t{
\t\t\t\t\tthis.currentState.setCursor(mxConstants.CURSOR_CONNECT);
\t\t\t\t\tme.consume();
\t\t\t\t}
\t\t\t}

\t\t\tthis.previous = this.currentState;
\t\t}
\t\telse if (this.previous == this.currentState && this.currentState != null && this.icons == null &&
\t\t\t!this.graph.isMouseDown)
\t\t{
\t\t\t// Makes sure that no cursors are changed
\t\t\tme.consume();
\t\t}

\t\tif (!this.graph.isMouseDown && this.currentState != null && this.icons != null)
\t\t{
\t\t\tvar hitsIcon = false;
\t\t\tvar target = me.getSource();
\t\t\t
\t\t\tfor (var i = 0; i < this.icons.length && !hitsIcon; i++)
\t\t\t{
\t\t\t\thitsIcon = target == this.icons[i].node || target.parentNode == this.icons[i].node;
\t\t\t}

\t\t\tif (!hitsIcon)
\t\t\t{
\t\t\t\tthis.updateIcons(this.currentState, this.icons, me);
\t\t\t}
\t\t}
\t}
\telse
\t{
\t\tthis.constraintHandler.reset();
\t}
};

/**
 * Function: updateEdgeState
 * 
 * Updates <edgeState>.
 */
mxConnectionHandler.prototype.updateEdgeState = function(current, constraint)
{
\t// TODO: Use generic method for writing constraint to style
\tif (this.sourceConstraint != null && this.sourceConstraint.point != null)
\t{
\t\tthis.edgeState.style[mxConstants.STYLE_EXIT_X] = this.sourceConstraint.point.x;
\t\tthis.edgeState.style[mxConstants.STYLE_EXIT_Y] = this.sourceConstraint.point.y;
\t}

\tif (constraint != null && constraint.point != null)
\t{
\t\tthis.edgeState.style[mxConstants.STYLE_ENTRY_X] = constraint.point.x;
\t\tthis.edgeState.style[mxConstants.STYLE_ENTRY_Y] = constraint.point.y;
\t}
\telse
\t{
\t\tdelete this.edgeState.style[mxConstants.STYLE_ENTRY_X];
\t\tdelete this.edgeState.style[mxConstants.STYLE_ENTRY_Y];
\t}
\t
\tthis.edgeState.absolutePoints = [null, (this.currentState != null) ? null : current];
\tthis.graph.view.updateFixedTerminalPoint(this.edgeState, this.previous, true, this.sourceConstraint);
\t
\tif (this.currentState != null)
\t{
\t\tif (constraint == null)
\t\t{
\t\t\tconstraint = this.graph.getConnectionConstraint(this.edgeState, this.previous, false);
\t\t}
\t\t
\t\tthis.edgeState.setAbsoluteTerminalPoint(null, false);
\t\tthis.graph.view.updateFixedTerminalPoint(this.edgeState, this.currentState, false, constraint);
\t}
\t
\t// Scales and translates the waypoints to the model
\tvar realPoints = null;
\t
\tif (this.waypoints != null)
\t{
\t\trealPoints = [];
\t\t
\t\tfor (var i = 0; i < this.waypoints.length; i++)
\t\t{
\t\t\tvar pt = this.waypoints[i].clone();
\t\t\tthis.convertWaypoint(pt);
\t\t\trealPoints[i] = pt;
\t\t}
\t}
\t
\tthis.graph.view.updatePoints(this.edgeState, realPoints, this.previous, this.currentState);
\tthis.graph.view.updateFloatingTerminalPoints(this.edgeState, this.previous, this.currentState);
};

/**
 * Function: getTargetPerimeterPoint
 * 
 * Returns the perimeter point for the given target state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the target cell state.
 * me - <mxMouseEvent> that represents the mouse move.
 */
mxConnectionHandler.prototype.getTargetPerimeterPoint = function(state, me)
{
\tvar result = null;
\tvar view = state.view;
\tvar targetPerimeter = view.getPerimeterFunction(state);
\t
\tif (targetPerimeter != null)
\t{
\t\tvar next = (this.waypoints != null && this.waypoints.length > 0) ?
\t\t\t\tthis.waypoints[this.waypoints.length - 1] :
\t\t\t\tnew mxPoint(this.previous.getCenterX(), this.previous.getCenterY());
\t\tvar tmp = targetPerimeter(view.getPerimeterBounds(state),
\t\t\tthis.edgeState, next, false);
\t\t\t
\t\tif (tmp != null)
\t\t{
\t\t\tresult = tmp;
\t\t}
\t}
\telse
\t{
\t\tresult = new mxPoint(state.getCenterX(), state.getCenterY());
\t}
\t
\treturn result;
};

/**
 * Function: getSourcePerimeterPoint
 * 
 * Hook to update the icon position(s) based on a mouseOver event. This is
 * an empty implementation.
 * 
 * Parameters:
 * 
 * state - <mxCellState> that represents the target cell state.
 * next - <mxPoint> that represents the next point along the previewed edge.
 * me - <mxMouseEvent> that represents the mouse move.
 */
mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, next, me)
{
\tvar result = null;
\tvar view = state.view;
\tvar sourcePerimeter = view.getPerimeterFunction(state);
\tvar c = new mxPoint(state.getCenterX(), state.getCenterY());
\t
\tif (sourcePerimeter != null)
\t{
\t\tvar theta = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0);
\t\tvar rad = -theta * (Math.PI / 180);
\t\t
\t\tif (theta != 0)
\t\t{
\t\t\tnext = mxUtils.getRotatedPoint(new mxPoint(next.x, next.y), Math.cos(rad), Math.sin(rad), c);
\t\t}
\t\t
\t\tvar tmp = sourcePerimeter(view.getPerimeterBounds(state), state, next, false);
\t\t\t
\t\tif (tmp != null)
\t\t{
\t\t\tif (theta != 0)
\t\t\t{
\t\t\t\ttmp = mxUtils.getRotatedPoint(new mxPoint(tmp.x, tmp.y), Math.cos(-rad), Math.sin(-rad), c);
\t\t\t}
\t\t\t
\t\t\tresult = tmp;
\t\t}
\t}
\telse
\t{
\t\tresult = c;
\t}
\t
\treturn result;
};


/**
 * Function: updateIcons
 * 
 * Hook to update the icon position(s) based on a mouseOver event. This is
 * an empty implementation.
 * 
 * Parameters:
 * 
 * state - <mxCellState> under the mouse.
 * icons - Array of currently displayed icons.
 * me - <mxMouseEvent> that contains the mouse event.
 */
mxConnectionHandler.prototype.updateIcons = function(state, icons, me)
{
\t// empty
};

/**
 * Function: isStopEvent
 * 
 * Returns true if the given mouse up event should stop this handler. The
 * connection will be created if <error> is null. Note that this is only
 * called if <waypointsEnabled> is true. This implemtation returns true
 * if there is a cell state in the given event.
 */
mxConnectionHandler.prototype.isStopEvent = function(me)
{
\treturn me.getState() != null;
};

/**
 * Function: addWaypoint
 * 
 * Adds the waypoint for the given event to <waypoints>.
 */
mxConnectionHandler.prototype.addWaypointForEvent = function(me)
{
\tvar point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
\tvar dx = Math.abs(point.x - this.first.x);
\tvar dy = Math.abs(point.y - this.first.y);
\tvar addPoint = this.waypoints != null || (this.mouseDownCounter > 1 &&
\t\t\t(dx > this.graph.tolerance || dy > this.graph.tolerance));

\tif (addPoint)
\t{
\t\tif (this.waypoints == null)
\t\t{
\t\t\tthis.waypoints = [];
\t\t}
\t\t
\t\tvar scale = this.graph.view.scale;
\t\tvar point = new mxPoint(this.graph.snap(me.getGraphX() / scale) * scale,
\t\t\t\tthis.graph.snap(me.getGraphY() / scale) * scale);
\t\tthis.waypoints.push(point);
\t}
};

/**
 * Function: checkConstraints
 * 
 * Returns true if the connection for the given constraints is valid. This
 * implementation returns true if the constraints are not pointing to the
 * same fixed connection point.
 */
mxConnectionHandler.prototype.checkConstraints = function(c1, c2)
{
\treturn (c1 == null || c2 == null || c1.point == null || c2.point == null ||
\t\t!c1.point.equals(c2.point) || c1.dx != c2.dx || c1.dy != c2.dy ||
\t\tc1.perimeter != c2.perimeter);
};

/**
 * Function: mouseUp
 * 
 * Handles the event by inserting the new connection.
 */
mxConnectionHandler.prototype.mouseUp = function(sender, me)
{
\tif (!me.isConsumed() && this.isConnecting())
\t{
\t\tif (this.waypointsEnabled && !this.isStopEvent(me))
\t\t{
\t\t\tthis.addWaypointForEvent(me);
\t\t\tme.consume();
\t\t\t
\t\t\treturn;
\t\t}
\t\t
\t\tvar c1 = this.sourceConstraint;
\t\tvar c2 = this.constraintHandler.currentConstraint;

\t\tvar source = (this.previous != null) ? this.previous.cell : null;
\t\tvar target = null;
\t\t
\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\tthis.constraintHandler.currentFocus != null)
\t\t{
\t\t\ttarget = this.constraintHandler.currentFocus.cell;
\t\t}
\t\t
\t\tif (target == null && this.currentState != null)
\t\t{
\t\t\ttarget = this.currentState.cell;
\t\t}
\t\t
\t\t// Inserts the edge if no validation error exists and if constraints differ
\t\tif (this.error == null && (source == null || target == null ||
\t\t\tsource != target || this.checkConstraints(c1, c2)))
\t\t{
\t\t\tthis.connect(source, target, me.getEvent(), me.getCell());
\t\t}
\t\telse
\t\t{
\t\t\t// Selects the source terminal for self-references
\t\t\tif (this.previous != null && this.marker.validState != null &&
\t\t\t\tthis.previous.cell == this.marker.validState.cell)
\t\t\t{
\t\t\t\tthis.graph.selectCellForEvent(this.marker.source, me.getEvent());
\t\t\t}
\t\t\t
\t\t\t// Displays the error message if it is not an empty string,
\t\t\t// for empty error messages, the event is silently dropped
\t\t\tif (this.error != null && this.error.length > 0)
\t\t\t{
\t\t\t\tthis.graph.validationAlert(this.error);
\t\t\t}
\t\t}
\t\t
\t\t// Redraws the connect icons and resets the handler state
\t\tthis.destroyIcons();
\t\tme.consume();
\t}

\tif (this.first != null)
\t{
\t\tthis.reset();
\t}
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxConnectionHandler.prototype.reset = function()
{
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
\t
\t// Resets the cursor on the container
\tif (this.cursor != null && this.graph.container != null)
\t{
\t\tthis.graph.container.style.cursor = '';
\t}
\t
\tthis.destroyIcons();
\tthis.marker.reset();
\tthis.constraintHandler.reset();
\tthis.originalPoint = null;
\tthis.currentPoint = null;
\tthis.edgeState = null;
\tthis.previous = null;
\tthis.error = null;
\tthis.sourceConstraint = null;
\tthis.mouseDownCounter = 0;
\tthis.first = null;

\tthis.fireEvent(new mxEventObject(mxEvent.RESET));
};

/**
 * Function: drawPreview
 * 
 * Redraws the preview edge using the color and width returned by
 * <getEdgeColor> and <getEdgeWidth>.
 */
mxConnectionHandler.prototype.drawPreview = function()
{
\tthis.updatePreview(this.error == null);
\tthis.shape.redraw();
};

/**
 * Function: getEdgeColor
 * 
 * Returns the color used to draw the preview edge. This returns green if
 * there is no edge validation error and red otherwise.
 * 
 * Parameters:
 * 
 * valid - Boolean indicating if the color for a valid edge should be
 * returned.
 */
mxConnectionHandler.prototype.updatePreview = function(valid)
{
\tthis.shape.strokewidth = this.getEdgeWidth(valid);
\tthis.shape.stroke = this.getEdgeColor(valid);
};

/**
 * Function: getEdgeColor
 * 
 * Returns the color used to draw the preview edge. This returns green if
 * there is no edge validation error and red otherwise.
 * 
 * Parameters:
 * 
 * valid - Boolean indicating if the color for a valid edge should be
 * returned.
 */
mxConnectionHandler.prototype.getEdgeColor = function(valid)
{
\treturn (valid) ? mxConstants.VALID_COLOR : mxConstants.INVALID_COLOR;
};
\t
/**
 * Function: getEdgeWidth
 * 
 * Returns the width used to draw the preview edge. This returns 3 if
 * there is no edge validation error and 1 otherwise.
 * 
 * Parameters:
 * 
 * valid - Boolean indicating if the width for a valid edge should be
 * returned.
 */
mxConnectionHandler.prototype.getEdgeWidth = function(valid)
{
\treturn (valid) ? 3 : 1;
};

/**
 * Function: connect
 * 
 * Connects the given source and target using a new edge. This
 * implementation uses <createEdge> to create the edge.
 * 
 * Parameters:
 * 
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 * evt - Mousedown event of the connect gesture.
 * dropTarget - <mxCell> that represents the cell under the mouse when it was
 * released.
 */
mxConnectionHandler.prototype.connect = function(source, target, evt, dropTarget)
{
\tif (target != null || this.isCreateTarget(evt) || this.graph.allowDanglingEdges)
\t{
\t\t// Uses the common parent of source and target or
\t\t// the default parent to insert the edge
\t\tvar model = this.graph.getModel();
\t\tvar terminalInserted = false;
\t\tvar edge = null;

\t\tmodel.beginUpdate();
\t\ttry
\t\t{
\t\t\tif (source != null && target == null && !this.graph.isIgnoreTerminalEvent(evt) && this.isCreateTarget(evt))
\t\t\t{
\t\t\t\ttarget = this.createTargetVertex(evt, source);
\t\t\t\t
\t\t\t\tif (target != null)
\t\t\t\t{
\t\t\t\t\tdropTarget = this.graph.getDropTarget([target], evt, dropTarget);
\t\t\t\t\tterminalInserted = true;
\t\t\t\t\t
\t\t\t\t\t// Disables edges as drop targets if the target cell was created
\t\t\t\t\t// FIXME: Should not shift if vertex was aligned (same in Java)
\t\t\t\t\tif (dropTarget == null || !this.graph.getModel().isEdge(dropTarget))
\t\t\t\t\t{
\t\t\t\t\t\tvar pstate = this.graph.getView().getState(dropTarget);
\t\t\t\t\t\t
\t\t\t\t\t\tif (pstate != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar tmp = model.getGeometry(target);
\t\t\t\t\t\t\ttmp.x -= pstate.origin.x;
\t\t\t\t\t\t\ttmp.y -= pstate.origin.y;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tdropTarget = this.graph.getDefaultParent();
\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\tthis.graph.addCell(target, dropTarget);
\t\t\t\t}
\t\t\t}

\t\t\tvar parent = this.graph.getDefaultParent();

\t\t\tif (source != null && target != null &&
\t\t\t\tmodel.getParent(source) == model.getParent(target) &&
\t\t\t\tmodel.getParent(model.getParent(source)) != model.getRoot())
\t\t\t{
\t\t\t\tparent = model.getParent(source);

\t\t\t\tif ((source.geometry != null && source.geometry.relative) &&
\t\t\t\t\t(target.geometry != null && target.geometry.relative))
\t\t\t\t{
\t\t\t\t\tparent = model.getParent(parent);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Uses the value of the preview edge state for inserting
\t\t\t// the new edge into the graph
\t\t\tvar value = null;
\t\t\tvar style = null;
\t\t\t
\t\t\tif (this.edgeState != null)
\t\t\t{
\t\t\t\tvalue = this.edgeState.cell.value;
\t\t\t\tstyle = this.edgeState.cell.style;
\t\t\t}

\t\t\tedge = this.insertEdge(parent, null, value, source, target, style);
\t\t\t
\t\t\tif (edge != null)
\t\t\t{
\t\t\t\t// Updates the connection constraints
\t\t\t\tthis.graph.setConnectionConstraint(edge, source, true, this.sourceConstraint);
\t\t\t\tthis.graph.setConnectionConstraint(edge, target, false, this.constraintHandler.currentConstraint);
\t\t\t\t
\t\t\t\t// Uses geometry of the preview edge state
\t\t\t\tif (this.edgeState != null)
\t\t\t\t{
\t\t\t\t\tmodel.setGeometry(edge, this.edgeState.cell.geometry);
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar parent = model.getParent(source);
\t\t\t\t
\t\t\t\t// Inserts edge before source
\t\t\t\tif (this.isInsertBefore(edge, source, target, evt, dropTarget))
\t\t\t\t{
\t\t\t\t\tvar index = null;
\t\t\t\t\tvar tmp = source;

\t\t\t\t\twhile (tmp.parent != null && tmp.geometry != null &&
\t\t\t\t\t\ttmp.geometry.relative && tmp.parent != edge.parent)
\t\t\t\t\t{
\t\t\t\t\t\ttmp = this.graph.model.getParent(tmp);
\t\t\t\t\t}

\t\t\t\t\tif (tmp != null && tmp.parent != null && tmp.parent == edge.parent)
\t\t\t\t\t{
\t\t\t\t\t\tmodel.add(parent, edge, tmp.parent.getIndex(tmp));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Makes sure the edge has a non-null, relative geometry
\t\t\t\tvar geo = model.getGeometry(edge);

\t\t\t\tif (geo == null)
\t\t\t\t{
\t\t\t\t\tgeo = new mxGeometry();
\t\t\t\t\tgeo.relative = true;
\t\t\t\t\t
\t\t\t\t\tmodel.setGeometry(edge, geo);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Uses scaled waypoints in geometry
\t\t\t\tif (this.waypoints != null && this.waypoints.length > 0)
\t\t\t\t{
\t\t\t\t\tvar s = this.graph.view.scale;
\t\t\t\t\tvar tr = this.graph.view.translate;
\t\t\t\t\tgeo.points = [];
\t\t\t\t\t
\t\t\t\t\tfor (var i = 0; i < this.waypoints.length; i++)
\t\t\t\t\t{
\t\t\t\t\t\tvar pt = this.waypoints[i];
\t\t\t\t\t\tgeo.points.push(new mxPoint(pt.x / s - tr.x, pt.y / s - tr.y));
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (target == null)
\t\t\t\t{
\t\t\t\t\tvar t = this.graph.view.translate;
\t\t\t\t\tvar s = this.graph.view.scale;
\t\t\t\t\tvar pt = (this.originalPoint != null) ?
\t\t\t\t\t\t\tnew mxPoint(this.originalPoint.x / s - t.x, this.originalPoint.y / s - t.y) :
\t\t\t\t\t\tnew mxPoint(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
\t\t\t\t\tpt.x -= this.graph.panDx / this.graph.view.scale;
\t\t\t\t\tpt.y -= this.graph.panDy / this.graph.view.scale;
\t\t\t\t\tgeo.setTerminalPoint(pt, false);
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.CONNECT, 'cell', edge, 'terminal', target,
\t\t\t\t\t'event', evt, 'target', dropTarget, 'terminalInserted', terminalInserted));
\t\t\t}
\t\t}
\t\tcatch (e)
\t\t{
\t\t\tmxLog.show();
\t\t\tmxLog.debug(e.message);
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t\t
\t\tif (this.select)
\t\t{
\t\t\tthis.selectCells(edge, (terminalInserted) ? target : null);
\t\t}
\t}
};

/**
 * Function: selectCells
 * 
 * Selects the given edge after adding a new connection. The target argument
 * contains the target vertex if one has been inserted.
 */
mxConnectionHandler.prototype.selectCells = function(edge, target)
{
\tthis.graph.setSelectionCell(edge);
};

/**
 * Function: insertEdge
 * 
 * Creates, inserts and returns the new edge for the given parameters. This
 * implementation does only use <createEdge> if <factoryMethod> is defined,
 * otherwise <mxGraph.insertEdge> will be used.
 */
mxConnectionHandler.prototype.insertEdge = function(parent, id, value, source, target, style)
{
\tif (this.factoryMethod == null)
\t{
\t\treturn this.graph.insertEdge(parent, id, value, source, target, style);
\t}
\telse
\t{
\t\tvar edge = this.createEdge(value, source, target, style);
\t\tedge = this.graph.addEdge(edge, parent, source, target);
\t\t
\t\treturn edge;
\t}
};

/**
 * Function: createTargetVertex
 * 
 * Hook method for creating new vertices on the fly if no target was
 * under the mouse. This is only called if <createTarget> is true and
 * returns null.
 * 
 * Parameters:
 * 
 * evt - Mousedown event of the connect gesture.
 * source - <mxCell> that represents the source terminal.
 */
mxConnectionHandler.prototype.createTargetVertex = function(evt, source)
{
\t// Uses the first non-relative source
\tvar geo = this.graph.getCellGeometry(source);
\t
\twhile (geo != null && geo.relative)
\t{
\t\tsource = this.graph.getModel().getParent(source);
\t\tgeo = this.graph.getCellGeometry(source);
\t}
\t
\tvar clone = this.graph.cloneCell(source);
\tvar geo = this.graph.getModel().getGeometry(clone);
\t
\tif (geo != null)
\t{
\t\tvar t = this.graph.view.translate;
\t\tvar s = this.graph.view.scale;
\t\tvar point = new mxPoint(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
\t\tgeo.x = Math.round(point.x - geo.width / 2 - this.graph.panDx / s);
\t\tgeo.y = Math.round(point.y - geo.height / 2 - this.graph.panDy / s);

\t\t// Aligns with source if within certain tolerance
\t\tvar tol = this.getAlignmentTolerance();
\t\t
\t\tif (tol > 0)
\t\t{
\t\t\tvar sourceState = this.graph.view.getState(source);
\t\t\t
\t\t\tif (sourceState != null)
\t\t\t{
\t\t\t\tvar x = sourceState.x / s - t.x;
\t\t\t\tvar y = sourceState.y / s - t.y;
\t\t\t\t
\t\t\t\tif (Math.abs(x - geo.x) <= tol)
\t\t\t\t{
\t\t\t\t\tgeo.x = Math.round(x);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (Math.abs(y - geo.y) <= tol)
\t\t\t\t{
\t\t\t\t\tgeo.y = Math.round(y);
\t\t\t\t}
\t\t\t}
\t\t}
\t}

\treturn clone;\t\t
};

/**
 * Function: getAlignmentTolerance
 * 
 * Returns the tolerance for aligning new targets to sources. This returns the grid size / 2.
 */
mxConnectionHandler.prototype.getAlignmentTolerance = function(evt)
{
\treturn (this.graph.isGridEnabled()) ? this.graph.gridSize / 2 : this.graph.tolerance;
};

/**
 * Function: createEdge
 * 
 * Creates and returns a new edge using <factoryMethod> if one exists. If
 * no factory method is defined, then a new default edge is returned. The
 * source and target arguments are informal, the actual connection is
 * setup later by the caller of this function.
 * 
 * Parameters:
 * 
 * value - Value to be used for creating the edge.
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 * style - Optional style from the preview edge.
 */
mxConnectionHandler.prototype.createEdge = function(value, source, target, style)
{
\tvar edge = null;
\t
\t// Creates a new edge using the factoryMethod
\tif (this.factoryMethod != null)
\t{
\t\tedge = this.factoryMethod(source, target, style);
\t}
\t
\tif (edge == null)
\t{
\t\tedge = new mxCell(value || '');
\t\tedge.setEdge(true);
\t\tedge.setStyle(style);
\t\t
\t\tvar geo = new mxGeometry();
\t\tgeo.relative = true;
\t\tedge.setGeometry(geo);
\t}

\treturn edge;
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes. This should be
 * called on all instances. It is called automatically for the built-in
 * instance created for each <mxGraph>.
 */
mxConnectionHandler.prototype.destroy = function()
{
\tthis.graph.removeMouseListener(this);
\t
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
\t
\tif (this.marker != null)
\t{
\t\tthis.marker.destroy();
\t\tthis.marker = null;
\t}

\tif (this.constraintHandler != null)
\t{
\t\tthis.constraintHandler.destroy();
\t\tthis.constraintHandler = null;
\t}

\tif (this.changeHandler != null)
\t{
\t\tthis.graph.getModel().removeListener(this.changeHandler);
\t\tthis.graph.getView().removeListener(this.changeHandler);
\t\tthis.changeHandler = null;
\t}
\t
\tif (this.drillHandler != null)
\t{
\t\tthis.graph.removeListener(this.drillHandler);
\t\tthis.graph.getView().removeListener(this.drillHandler);
\t\tthis.drillHandler = null;
\t}
\t
\tif (this.escapeHandler != null)
\t{
\t\tthis.graph.removeListener(this.escapeHandler);
\t\tthis.escapeHandler = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxConstraintHandler
 *
 * Handles constraints on connection targets. This class is in charge of
 * showing fixed points when the mouse is over a vertex and handles constraints
 * to establish new connections.
 *
 * Constructor: mxConstraintHandler
 *
 * Constructs an new constraint handler.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * factoryMethod - Optional function to create the edge. The function takes
 * the source and target <mxCell> as the first and second argument and
 * returns the <mxCell> that represents the new edge.
 */
function mxConstraintHandler(graph)
{
\tthis.graph = graph;
\t
\t// Adds a graph model listener to update the current focus on changes
\tthis.resetHandler = mxUtils.bind(this, function(sender, evt)
\t{
\t\tif (this.currentFocus != null && this.graph.view.getState(this.currentFocus.cell) == null)
\t\t{
\t\t\tthis.reset();
\t\t}
\t\telse
\t\t{
\t\t\tthis.redraw();
\t\t}
\t});
\t
\tthis.graph.model.addListener(mxEvent.CHANGE, this.resetHandler);
\tthis.graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.resetHandler);
\tthis.graph.view.addListener(mxEvent.TRANSLATE, this.resetHandler);
\tthis.graph.view.addListener(mxEvent.SCALE, this.resetHandler);
\tthis.graph.addListener(mxEvent.ROOT, this.resetHandler);
};

/**
 * Variable: pointImage
 * 
 * <mxImage> to be used as the image for fixed connection points.
 */
mxConstraintHandler.prototype.pointImage = new mxImage(mxClient.imageBasePath + '/point.gif', 5, 5);

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxConstraintHandler.prototype.graph = null;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxConstraintHandler.prototype.enabled = true;

/**
 * Variable: highlightColor
 * 
 * Specifies the color for the highlight. Default is <mxConstants.DEFAULT_VALID_COLOR>.
 */
mxConstraintHandler.prototype.highlightColor = mxConstants.DEFAULT_VALID_COLOR;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxConstraintHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};
\t
/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxConstraintHandler.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxConstraintHandler.prototype.reset = function()
{
\tif (this.focusIcons != null)
\t{
\t\tfor (var i = 0; i < this.focusIcons.length; i++)
\t\t{
\t\t\tthis.focusIcons[i].destroy();
\t\t}
\t\t
\t\tthis.focusIcons = null;
\t}
\t
\tif (this.focusHighlight != null)
\t{
\t\tthis.focusHighlight.destroy();
\t\tthis.focusHighlight = null;
\t}
\t
\tthis.currentConstraint = null;
\tthis.currentFocusArea = null;
\tthis.currentPoint = null;
\tthis.currentFocus = null;
\tthis.focusPoints = null;
};

/**
 * Function: getTolerance
 * 
 * Returns the tolerance to be used for intersecting connection points. This
 * implementation returns <mxGraph.tolerance>.
 * 
 * Parameters:
 * 
 * me - <mxMouseEvent> whose tolerance should be returned.
 */
mxConstraintHandler.prototype.getTolerance = function(me)
{
\treturn this.graph.getTolerance();
};

/**
 * Function: getImageForConstraint
 * 
 * Returns the tolerance to be used for intersecting connection points.
 */
mxConstraintHandler.prototype.getImageForConstraint = function(state, constraint, point)
{
\treturn this.pointImage;
};

/**
 * Function: isEventIgnored
 * 
 * Returns true if the given <mxMouseEvent> should be ignored in <update>. This
 * implementation always returns false.
 */
mxConstraintHandler.prototype.isEventIgnored = function(me, source)
{
\treturn false;
};

/**
 * Function: isStateIgnored
 * 
 * Returns true if the given state should be ignored. This always returns false.
 */
mxConstraintHandler.prototype.isStateIgnored = function(state, source)
{
\treturn false;
};

/**
 * Function: destroyIcons
 * 
 * Destroys the <focusIcons> if they exist.
 */
mxConstraintHandler.prototype.destroyIcons = function()
{
\tif (this.focusIcons != null)
\t{
\t\tfor (var i = 0; i < this.focusIcons.length; i++)
\t\t{
\t\t\tthis.focusIcons[i].destroy();
\t\t}
\t\t
\t\tthis.focusIcons = null;
\t\tthis.focusPoints = null;
\t}
};

/**
 * Function: destroyFocusHighlight
 * 
 * Destroys the <focusHighlight> if one exists.
 */
mxConstraintHandler.prototype.destroyFocusHighlight = function()
{
\tif (this.focusHighlight != null)
\t{
\t\tthis.focusHighlight.destroy();
\t\tthis.focusHighlight = null;
\t}
};

/**
 * Function: isKeepFocusEvent
 * 
 * Returns true if the current focused state should not be changed for the given event.
 * This returns true if shift and alt are pressed.
 */
mxConstraintHandler.prototype.isKeepFocusEvent = function(me)
{
\treturn mxEvent.isShiftDown(me.getEvent());
};

/**
 * Function: getCellForEvent
 * 
 * Returns the cell for the given event.
 */
mxConstraintHandler.prototype.getCellForEvent = function(me, point)
{
\tvar cell = me.getCell();
\t
\t// Gets cell under actual point if different from event location
\tif (cell == null && point != null && (me.getGraphX() != point.x || me.getGraphY() != point.y))
\t{
\t\tcell = this.graph.getCellAt(point.x, point.y);
\t}
\t
\t// Uses connectable parent vertex if one exists
\tif (cell != null && !this.graph.isCellConnectable(cell))
\t{
\t\tvar parent = this.graph.getModel().getParent(cell);
\t\t
\t\tif (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
\t\t{
\t\t\tcell = parent;
\t\t}
\t}
\t
\treturn (this.graph.isCellLocked(cell)) ? null : cell;
};

/**
 * Function: update
 * 
 * Updates the state of this handler based on the given <mxMouseEvent>.
 * Source is a boolean indicating if the cell is a source or target.
 */
mxConstraintHandler.prototype.update = function(me, source, existingEdge, point)
{
\tif (this.isEnabled() && !this.isEventIgnored(me))
\t{
\t\t// Lazy installation of mouseleave handler
\t\tif (this.mouseleaveHandler == null && this.graph.container != null)
\t\t{
\t\t\tthis.mouseleaveHandler = mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tthis.reset();
\t\t\t});

\t\t\tmxEvent.addListener(this.graph.container, 'mouseleave', this.resetHandler);\t
\t\t}
\t\t
\t\tvar tol = this.getTolerance(me);
\t\tvar x = (point != null) ? point.x : me.getGraphX();
\t\tvar y = (point != null) ? point.y : me.getGraphY();
\t\tvar grid = new mxRectangle(x - tol, y - tol, 2 * tol, 2 * tol);
\t\tvar mouse = new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol);
\t\tvar state = this.graph.view.getState(this.getCellForEvent(me, point));

\t\t// Keeps focus icons visible while over vertex bounds and no other cell under mouse or shift is pressed
\t\tif (!this.isKeepFocusEvent(me) && (this.currentFocusArea == null || this.currentFocus == null ||
\t\t\t(state != null) || !this.graph.getModel().isVertex(this.currentFocus.cell) ||
\t\t\t!mxUtils.intersects(this.currentFocusArea, mouse)) && (state != this.currentFocus))
\t\t{
\t\t\tthis.currentFocusArea = null;
\t\t\tthis.currentFocus = null;
\t\t\tthis.setFocus(me, state, source);
\t\t}

\t\tthis.currentConstraint = null;
\t\tthis.currentPoint = null;
\t\tvar minDistSq = null;
\t\t
\t\tif (this.focusIcons != null && this.constraints != null &&
\t\t\t(state == null || this.currentFocus == state))
\t\t{
\t\t\tvar cx = mouse.getCenterX();
\t\t\tvar cy = mouse.getCenterY();
\t\t\t
\t\t\tfor (var i = 0; i < this.focusIcons.length; i++)
\t\t\t{
\t\t\t\tvar dx = cx - this.focusIcons[i].bounds.getCenterX();
\t\t\t\tvar dy = cy - this.focusIcons[i].bounds.getCenterY();
\t\t\t\tvar tmp = dx * dx + dy * dy;
\t\t\t\t
\t\t\t\tif ((this.intersects(this.focusIcons[i], mouse, source, existingEdge) || (point != null &&
\t\t\t\t\tthis.intersects(this.focusIcons[i], grid, source, existingEdge))) &&
\t\t\t\t\t(minDistSq == null || tmp < minDistSq))
\t\t\t\t{
\t\t\t\t\tthis.currentConstraint = this.constraints[i];
\t\t\t\t\tthis.currentPoint = this.focusPoints[i];
\t\t\t\t\tminDistSq = tmp;
\t\t\t\t\t
\t\t\t\t\tvar tmp = this.focusIcons[i].bounds.clone();
\t\t\t\t\ttmp.grow(mxConstants.HIGHLIGHT_SIZE + 1);
\t\t\t\t\ttmp.width -= 1;
\t\t\t\t\ttmp.height -= 1;
\t\t\t\t\t
\t\t\t\t\tif (this.focusHighlight == null)
\t\t\t\t\t{
\t\t\t\t\t\tvar hl = this.createHighlightShape();
\t\t\t\t\t\thl.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ?
\t\t\t\t\t\t\t\tmxConstants.DIALECT_SVG : mxConstants.DIALECT_VML;
\t\t\t\t\t\thl.pointerEvents = false;

\t\t\t\t\t\thl.init(this.graph.getView().getOverlayPane());
\t\t\t\t\t\tthis.focusHighlight = hl;
\t\t\t\t\t\t
\t\t\t\t\t\tvar getState = mxUtils.bind(this, function()
\t\t\t\t\t\t{
\t\t\t\t\t\t\treturn (this.currentFocus != null) ? this.currentFocus : state;
\t\t\t\t\t\t});
\t
\t\t\t\t\t\tmxEvent.redirectMouseEvents(hl.node, this.graph, getState);
\t\t\t\t\t}

\t\t\t\t\tthis.focusHighlight.bounds = tmp;
\t\t\t\t\tthis.focusHighlight.redraw();
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (this.currentConstraint == null)
\t\t{
\t\t\tthis.destroyFocusHighlight();
\t\t}
\t}
\telse
\t{
\t\tthis.currentConstraint = null;
\t\tthis.currentFocus = null;
\t\tthis.currentPoint = null;
\t}
};

/**
 * Function: redraw
 * 
 * Transfers the focus to the given state as a source or target terminal. If
 * the handler is not enabled then the outline is painted, but the constraints
 * are ignored.
 */
mxConstraintHandler.prototype.redraw = function()
{
\tif (this.currentFocus != null && this.constraints != null && this.focusIcons != null)
\t{
\t\tvar state = this.graph.view.getState(this.currentFocus.cell);
\t\tthis.currentFocus = state;
\t\tthis.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
\t\t
\t\tfor (var i = 0; i < this.constraints.length; i++)
\t\t{
\t\t\tvar cp = this.graph.getConnectionPoint(state, this.constraints[i]);
\t\t\tvar img = this.getImageForConstraint(state, this.constraints[i], cp);

\t\t\tvar bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
\t\t\t\tMath.round(cp.y - img.height / 2), img.width, img.height);
\t\t\tthis.focusIcons[i].bounds = bounds;
\t\t\tthis.focusIcons[i].redraw();
\t\t\tthis.currentFocusArea.add(this.focusIcons[i].bounds);
\t\t\tthis.focusPoints[i] = cp;
\t\t}
\t}\t
};

/**
 * Function: setFocus
 * 
 * Transfers the focus to the given state as a source or target terminal. If
 * the handler is not enabled then the outline is painted, but the constraints
 * are ignored.
 */
mxConstraintHandler.prototype.setFocus = function(me, state, source)
{
\tthis.constraints = (state != null && !this.isStateIgnored(state, source) &&
\t\tthis.graph.isCellConnectable(state.cell)) ? ((this.isEnabled()) ?
\t\t(this.graph.getAllConnectionConstraints(state, source) || []) : []) : null;

\t// Only uses cells which have constraints
\tif (this.constraints != null)
\t{
\t\tthis.currentFocus = state;
\t\tthis.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
\t\t
\t\tif (this.focusIcons != null)
\t\t{
\t\t\tfor (var i = 0; i < this.focusIcons.length; i++)
\t\t\t{
\t\t\t\tthis.focusIcons[i].destroy();
\t\t\t}
\t\t\t
\t\t\tthis.focusIcons = null;
\t\t\tthis.focusPoints = null;
\t\t}
\t\t
\t\tthis.focusPoints = [];
\t\tthis.focusIcons = [];
\t\t
\t\tfor (var i = 0; i < this.constraints.length; i++)
\t\t{
\t\t\tvar cp = this.graph.getConnectionPoint(state, this.constraints[i]);
\t\t\tvar img = this.getImageForConstraint(state, this.constraints[i], cp);

\t\t\tvar src = img.src;
\t\t\tvar bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
\t\t\t\tMath.round(cp.y - img.height / 2), img.width, img.height);
\t\t\tvar icon = new mxImageShape(bounds, src);
\t\t\ticon.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\t\t\tmxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
\t\t\ticon.preserveImageAspect = false;
\t\t\ticon.init(this.graph.getView().getDecoratorPane());
\t\t\t
\t\t\t// Fixes lost event tracking for images in quirks / IE8 standards
\t\t\tif (mxClient.IS_QUIRKS || document.documentMode == 8)
\t\t\t{
\t\t\t\tmxEvent.addListener(icon.node, 'dragstart', function(evt)
\t\t\t\t{
\t\t\t\t\tmxEvent.consume(evt);
\t\t\t\t\t
\t\t\t\t\treturn false;
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t\t// Move the icon behind all other overlays
\t\t\tif (icon.node.previousSibling != null)
\t\t\t{
\t\t\t\ticon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
\t\t\t}

\t\t\tvar getState = mxUtils.bind(this, function()
\t\t\t{
\t\t\t\treturn (this.currentFocus != null) ? this.currentFocus : state;
\t\t\t});
\t\t\t
\t\t\ticon.redraw();

\t\t\tmxEvent.redirectMouseEvents(icon.node, this.graph, getState);
\t\t\tthis.currentFocusArea.add(icon.bounds);
\t\t\tthis.focusIcons.push(icon);
\t\t\tthis.focusPoints.push(cp);
\t\t}
\t\t
\t\tthis.currentFocusArea.grow(this.getTolerance(me));
\t}
\telse
\t{
\t\tthis.destroyIcons();
\t\tthis.destroyFocusHighlight();
\t}
};

/**
 * Function: createHighlightShape
 * 
 * Create the shape used to paint the highlight.
 * 
 * Returns true if the given icon intersects the given point.
 */
mxConstraintHandler.prototype.createHighlightShape = function()
{
\tvar hl = new mxRectangleShape(null, this.highlightColor, this.highlightColor, mxConstants.HIGHLIGHT_STROKEWIDTH);
\thl.opacity = mxConstants.HIGHLIGHT_OPACITY;
\t
\treturn hl;
};

/**
 * Function: intersects
 * 
 * Returns true if the given icon intersects the given rectangle.
 */
mxConstraintHandler.prototype.intersects = function(icon, mouse, source, existingEdge)
{
\treturn mxUtils.intersects(icon.bounds, mouse);
};

/**
 * Function: destroy
 * 
 * Destroy this handler.
 */
mxConstraintHandler.prototype.destroy = function()
{
\tthis.reset();
\t
\tif (this.resetHandler != null)
\t{
\t\tthis.graph.model.removeListener(this.resetHandler);
\t\tthis.graph.view.removeListener(this.resetHandler);
\t\tthis.graph.removeListener(this.resetHandler);
\t\tthis.resetHandler = null;
\t}
\t
\tif (this.mouseleaveHandler != null && this.graph.container != null)
\t{
\t\tmxEvent.removeListener(this.graph.container, 'mouseleave', this.mouseleaveHandler);
\t\tthis.mouseleaveHandler = null;
\t}
};
/**
 * Copyright (c) 2006-2016, JGraph Ltd
 * Copyright (c) 2006-2016, Gaudenz Alder
 */
/**
 * Class: mxRubberband
 * 
 * Event handler that selects rectangular regions. This is not built-into
 * <mxGraph>. To enable rubberband selection in a graph, use the following code.
 * 
 * Example:
 * 
 * (code)
 * var rubberband = new mxRubberband(graph);
 * (end)
 * 
 * Constructor: mxRubberband
 * 
 * Constructs an event handler that selects rectangular regions in the graph
 * using rubberband selection.
 */
function mxRubberband(graph)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.graph.addMouseListener(this);

\t\t// Handles force rubberband event
\t\tthis.forceRubberbandHandler = mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tvar evtName = evt.getProperty('eventName');
\t\t\tvar me = evt.getProperty('event');
\t\t\t
\t\t\tif (evtName == mxEvent.MOUSE_DOWN && this.isForceRubberbandEvent(me))
\t\t\t{
\t\t\t\tvar offset = mxUtils.getOffset(this.graph.container);
\t\t\t\tvar origin = mxUtils.getScrollOrigin(this.graph.container);
\t\t\t\torigin.x -= offset.x;
\t\t\t\torigin.y -= offset.y;
\t\t\t\tthis.start(me.getX() + origin.x, me.getY() + origin.y);
\t\t\t\tme.consume(false);
\t\t\t}
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forceRubberbandHandler);
\t\t
\t\t// Repaints the marquee after autoscroll
\t\tthis.panHandler = mxUtils.bind(this, function()
\t\t{
\t\t\tthis.repaint();
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.PAN, this.panHandler);
\t\t
\t\t// Does not show menu if any touch gestures take place after the trigger
\t\tthis.gestureHandler = mxUtils.bind(this, function(sender, eo)
\t\t{
\t\t\tif (this.first != null)
\t\t\t{
\t\t\t\tthis.reset();
\t\t\t}
\t\t});
\t\t
\t\tthis.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
\t\t
\t\t// Automatic deallocation of memory
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\tmxEvent.addListener(window, 'unload',
\t\t\t\tmxUtils.bind(this, function()
\t\t\t\t{
\t\t\t\t\tthis.destroy();
\t\t\t\t})
\t\t\t);
\t\t}
\t}
};

/**
 * Variable: defaultOpacity
 * 
 * Specifies the default opacity to be used for the rubberband div. Default
 * is 20.
 */
mxRubberband.prototype.defaultOpacity = 20;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxRubberband.prototype.enabled = true;

/**
 * Variable: div
 * 
 * Holds the DIV element which is currently visible.
 */
mxRubberband.prototype.div = null;

/**
 * Variable: sharedDiv
 * 
 * Holds the DIV element which is used to display the rubberband.
 */
mxRubberband.prototype.sharedDiv = null;

/**
 * Variable: currentX
 * 
 * Holds the value of the x argument in the last call to <update>.
 */
mxRubberband.prototype.currentX = 0;

/**
 * Variable: currentY
 * 
 * Holds the value of the y argument in the last call to <update>.
 */
mxRubberband.prototype.currentY = 0;

/**
 * Variable: fadeOut
 * 
 * Optional fade out effect. Default is false.
 */
mxRubberband.prototype.fadeOut = false;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation returns
 * <enabled>.
 */
mxRubberband.prototype.isEnabled = function()
{
\treturn this.enabled;
};
\t\t
/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation updates
 * <enabled>.
 */
mxRubberband.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isForceRubberbandEvent
 * 
 * Returns true if the given <mxMouseEvent> should start rubberband selection.
 * This implementation returns true if the alt key is pressed.
 */
mxRubberband.prototype.isForceRubberbandEvent = function(me)
{
\treturn mxEvent.isAltDown(me.getEvent());
};

/**
 * Function: mouseDown
 * 
 * Handles the event by initiating a rubberband selection. By consuming the
 * event all subsequent events of the gesture are redirected to this
 * handler.
 */
mxRubberband.prototype.mouseDown = function(sender, me)
{
\tif (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
\t\tme.getState() == null && !mxEvent.isMultiTouchEvent(me.getEvent()))
\t{
\t\tvar offset = mxUtils.getOffset(this.graph.container);
\t\tvar origin = mxUtils.getScrollOrigin(this.graph.container);
\t\torigin.x -= offset.x;
\t\torigin.y -= offset.y;
\t\tthis.start(me.getX() + origin.x, me.getY() + origin.y);

\t\t// Does not prevent the default for this event so that the
\t\t// event processing chain is still executed even if we start
\t\t// rubberbanding. This is required eg. in ExtJs to hide the
\t\t// current context menu. In mouseMove we'll make sure we're
\t\t// not selecting anything while we're rubberbanding.
\t\tme.consume(false);
\t}
};

/**
 * Function: start
 * 
 * Sets the start point for the rubberband selection.
 */
mxRubberband.prototype.start = function(x, y)
{
\tthis.first = new mxPoint(x, y);

\tvar container = this.graph.container;
\t
\tfunction createMouseEvent(evt)
\t{
\t\tvar me = new mxMouseEvent(evt);
\t\tvar pt = mxUtils.convertPoint(container, me.getX(), me.getY());
\t\t
\t\tme.graphX = pt.x;
\t\tme.graphY = pt.y;
\t\t
\t\treturn me;
\t};

\tthis.dragHandler = mxUtils.bind(this, function(evt)
\t{
\t\tthis.mouseMove(this.graph, createMouseEvent(evt));
\t});

\tthis.dropHandler = mxUtils.bind(this, function(evt)
\t{
\t\tthis.mouseUp(this.graph, createMouseEvent(evt));
\t});

\t// Workaround for rubberband stopping if the mouse leaves the container in Firefox
\tif (mxClient.IS_FF)
\t{
\t\tmxEvent.addGestureListeners(document, null, this.dragHandler, this.dropHandler);
\t}
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating therubberband selection.
 */
mxRubberband.prototype.mouseMove = function(sender, me)
{
\tif (!me.isConsumed() && this.first != null)
\t{
\t\tvar origin = mxUtils.getScrollOrigin(this.graph.container);
\t\tvar offset = mxUtils.getOffset(this.graph.container);
\t\torigin.x -= offset.x;
\t\torigin.y -= offset.y;
\t\tvar x = me.getX() + origin.x;
\t\tvar y = me.getY() + origin.y;
\t\tvar dx = this.first.x - x;
\t\tvar dy = this.first.y - y;
\t\tvar tol = this.graph.tolerance;
\t\t
\t\tif (this.div != null || Math.abs(dx) > tol ||  Math.abs(dy) > tol)
\t\t{
\t\t\tif (this.div == null)
\t\t\t{
\t\t\t\tthis.div = this.createShape();
\t\t\t}
\t\t\t
\t\t\t// Clears selection while rubberbanding. This is required because
\t\t\t// the event is not consumed in mouseDown.
\t\t\tmxUtils.clearSelection();
\t\t\t
\t\t\tthis.update(x, y);
\t\t\tme.consume();
\t\t}
\t}
};

/**
 * Function: createShape
 * 
 * Creates the rubberband selection shape.
 */
mxRubberband.prototype.createShape = function()
{
\tif (this.sharedDiv == null)
\t{
\t\tthis.sharedDiv = document.createElement('div');
\t\tthis.sharedDiv.className = 'mxRubberband';
\t\tmxUtils.setOpacity(this.sharedDiv, this.defaultOpacity);
\t}

\tthis.graph.container.appendChild(this.sharedDiv);
\tvar result = this.sharedDiv;
\t
\tif (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
\t{
\t\tthis.sharedDiv = null;
\t}
\t\t
\treturn result;
};

/**
 * Function: isActive
 * 
 * Returns true if this handler is active.
 */
mxRubberband.prototype.isActive = function(sender, me)
{
\treturn this.div != null && this.div.style.display != 'none';
};

/**
 * Function: mouseUp
 * 
 * Handles the event by selecting the region of the rubberband using
 * <mxGraph.selectRegion>.
 */
mxRubberband.prototype.mouseUp = function(sender, me)
{
\tvar active = this.isActive();
\tthis.reset();
\t
\tif (active)
\t{
\t\tthis.execute(me.getEvent());
\t\tme.consume();
\t}
};

/**
 * Function: execute
 * 
 * Resets the state of this handler and selects the current region
 * for the given event.
 */
mxRubberband.prototype.execute = function(evt)
{
\tvar rect = new mxRectangle(this.x, this.y, this.width, this.height);
\tthis.graph.selectRegion(rect, evt);
};

/**
 * Function: reset
 * 
 * Resets the state of the rubberband selection.
 */
mxRubberband.prototype.reset = function()
{
\tif (this.div != null)
\t{
\t\tif (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
\t\t{
\t\t\tvar temp = this.div;
\t\t\tmxUtils.setPrefixedStyle(temp.style, 'transition', 'all 0.2s linear');
\t\t\ttemp.style.pointerEvents = 'none';
\t\t\ttemp.style.opacity = 0;
\t\t    
\t\t    window.setTimeout(function()
\t\t    \t{
\t\t    \t\ttemp.parentNode.removeChild(temp);
\t\t    \t}, 200);\t
\t\t}
\t\telse
\t\t{
\t\t\tthis.div.parentNode.removeChild(this.div);
\t\t}
\t}

\tmxEvent.removeGestureListeners(document, null, this.dragHandler, this.dropHandler);
\tthis.dragHandler = null;
\tthis.dropHandler = null;
\t
\tthis.currentX = 0;
\tthis.currentY = 0;
\tthis.first = null;
\tthis.div = null;
};

/**
 * Function: update
 * 
 * Sets <currentX> and <currentY> and calls <repaint>.
 */
mxRubberband.prototype.update = function(x, y)
{
\tthis.currentX = x;
\tthis.currentY = y;
\t
\tthis.repaint();
};

/**
 * Function: repaint
 * 
 * Computes the bounding box and updates the style of the <div>.
 */
mxRubberband.prototype.repaint = function()
{
\tif (this.div != null)
\t{
\t\tvar x = this.currentX - this.graph.panDx;
\t\tvar y = this.currentY - this.graph.panDy;
\t\t
\t\tthis.x = Math.min(this.first.x, x);
\t\tthis.y = Math.min(this.first.y, y);
\t\tthis.width = Math.max(this.first.x, x) - this.x;
\t\tthis.height =  Math.max(this.first.y, y) - this.y;

\t\tvar dx = (mxClient.IS_VML) ? this.graph.panDx : 0;
\t\tvar dy = (mxClient.IS_VML) ? this.graph.panDy : 0;
\t\t
\t\tthis.div.style.left = (this.x + dx) + 'px';
\t\tthis.div.style.top = (this.y + dy) + 'px';
\t\tthis.div.style.width = Math.max(1, this.width) + 'px';
\t\tthis.div.style.height = Math.max(1, this.height) + 'px';
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes. This does
 * normally not need to be called, it is called automatically when the
 * window unloads.
 */
mxRubberband.prototype.destroy = function()
{
\tif (!this.destroyed)
\t{
\t\tthis.destroyed = true;
\t\tthis.graph.removeMouseListener(this);
\t\tthis.graph.removeListener(this.forceRubberbandHandler);
\t\tthis.graph.removeListener(this.panHandler);
\t\tthis.reset();
\t\t
\t\tif (this.sharedDiv != null)
\t\t{
\t\t\tthis.sharedDiv = null;
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxHandle
 * 
 * Implements a single custom handle for vertices.
 * 
 * Constructor: mxHandle
 * 
 * Constructs a new handle for the given state.
 * 
 * Parameters:
 * 
 * state - <mxCellState> of the cell to be handled.
 */
function mxHandle(state, cursor, image, shape)
{
\tthis.graph = state.view.graph;
\tthis.state = state;
\tthis.cursor = (cursor != null) ? cursor : this.cursor;
\tthis.image = (image != null) ? image : this.image;
\tthis.shape = (shape != null) ? shape : null;
\tthis.init();
};

/**
 * Variable: cursor
 * 
 * Specifies the cursor to be used for this handle. Default is 'default'.
 */
mxHandle.prototype.cursor = 'default';

/**
 * Variable: image
 * 
 * Specifies the <mxImage> to be used to render the handle. Default is null.
 */
mxHandle.prototype.image = null;

/**
 * Variable: ignoreGrid
 * 
 * Default is false.
 */
mxHandle.prototype.ignoreGrid = false;

/**
 * Function: getPosition
 * 
 * Hook for subclassers to return the current position of the handle.
 */
mxHandle.prototype.getPosition = function(bounds) { };

/**
 * Function: setPosition
 * 
 * Hooks for subclassers to update the style in the <state>.
 */
mxHandle.prototype.setPosition = function(bounds, pt, me) { };

/**
 * Function: execute
 * 
 * Hook for subclassers to execute the handle.
 */
mxHandle.prototype.execute = function(me) { };

/**
 * Function: copyStyle
 * 
 * Sets the cell style with the given name to the corresponding value in <state>.
 */
mxHandle.prototype.copyStyle = function(key)
{
\tthis.graph.setCellStyles(key, this.state.style[key], [this.state.cell]);
};

/**
 * Function: processEvent
 * 
 * Processes the given <mxMouseEvent> and invokes <setPosition>.
 */
mxHandle.prototype.processEvent = function(me)
{
\tvar scale = this.graph.view.scale;
\tvar tr = this.graph.view.translate;
\tvar pt = new mxPoint(me.getGraphX() / scale - tr.x, me.getGraphY() / scale - tr.y);
\t
\t// Center shape on mouse cursor
\tif (this.shape != null && this.shape.bounds != null)
\t{
\t\tpt.x -= this.shape.bounds.width / scale / 4;
\t\tpt.y -= this.shape.bounds.height / scale / 4;
\t}

\t// Snaps to grid for the rotated position then applies the rotation for the direction after that
\tvar alpha1 = -mxUtils.toRadians(this.getRotation());
\tvar alpha2 = -mxUtils.toRadians(this.getTotalRotation()) - alpha1;
\tpt = this.flipPoint(this.rotatePoint(this.snapPoint(this.rotatePoint(pt, alpha1),
\t\t\tthis.ignoreGrid || !this.graph.isGridEnabledEvent(me.getEvent())), alpha2));
\tthis.setPosition(this.state.getPaintBounds(), pt, me);
\tthis.redraw();
};

/**
 * Function: positionChanged
 * 
 * Should be called after <setPosition> in <processEvent>.
 * This repaints the state using <mxCellRenderer>.
 */
mxHandle.prototype.positionChanged = function()
{
\tif (this.state.text != null)
\t{
\t\tthis.state.text.apply(this.state);
\t}
\t
\tif (this.state.shape != null)
\t{
\t\tthis.state.shape.apply(this.state);
\t}
\t
\tthis.graph.cellRenderer.redraw(this.state, true);
};

/**
 * Function: getRotation
 * 
 * Returns the rotation defined in the style of the cell.
 */
mxHandle.prototype.getRotation = function()
{
\tif (this.state.shape != null)
\t{
\t\treturn this.state.shape.getRotation();
\t}
\t
\treturn 0;
};

/**
 * Function: getTotalRotation
 * 
 * Returns the rotation from the style and the rotation from the direction of
 * the cell.
 */
mxHandle.prototype.getTotalRotation = function()
{
\tif (this.state.shape != null)
\t{
\t\treturn this.state.shape.getShapeRotation();
\t}
\t
\treturn 0;
};

/**
 * Function: init
 * 
 * Creates and initializes the shapes required for this handle.
 */
mxHandle.prototype.init = function()
{
\tvar html = this.isHtmlRequired();
\t
\tif (this.image != null)
\t{
\t\tthis.shape = new mxImageShape(new mxRectangle(0, 0, this.image.width, this.image.height), this.image.src);
\t\tthis.shape.preserveImageAspect = false;
\t}
\telse if (this.shape == null)
\t{
\t\tthis.shape = this.createShape(html);
\t}
\t
\tthis.initShape(html);
};

/**
 * Function: createShape
 * 
 * Creates and returns the shape for this handle.
 */
mxHandle.prototype.createShape = function(html)
{
\tvar bounds = new mxRectangle(0, 0, mxConstants.HANDLE_SIZE, mxConstants.HANDLE_SIZE);
\t
\treturn new mxRectangleShape(bounds, mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
};

/**
 * Function: initShape
 * 
 * Initializes <shape> and sets its cursor.
 */
mxHandle.prototype.initShape = function(html)
{
\tif (html && this.shape.isHtmlAllowed())
\t{
\t\tthis.shape.dialect = mxConstants.DIALECT_STRICTHTML;
\t\tthis.shape.init(this.graph.container);
\t}
\telse
\t{
\t\tthis.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\tmxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
\t\t
\t\tif (this.cursor != null)
\t\t{
\t\t\tthis.shape.init(this.graph.getView().getOverlayPane());
\t\t}
\t}

\tmxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);
\tthis.shape.node.style.cursor = this.cursor;
};

/**
 * Function: redraw
 * 
 * Renders the shape for this handle.
 */
mxHandle.prototype.redraw = function()
{
\tif (this.shape != null && this.state.shape != null)
\t{
\t\tvar pt = this.getPosition(this.state.getPaintBounds());
\t\t
\t\tif (pt != null)
\t\t{
\t\t\tvar alpha = mxUtils.toRadians(this.getTotalRotation());
\t\t\tpt = this.rotatePoint(this.flipPoint(pt), alpha);
\t
\t\t\tvar scale = this.graph.view.scale;
\t\t\tvar tr = this.graph.view.translate;
\t\t\tthis.shape.bounds.x = Math.floor((pt.x + tr.x) * scale - this.shape.bounds.width / 2);
\t\t\tthis.shape.bounds.y = Math.floor((pt.y + tr.y) * scale - this.shape.bounds.height / 2);
\t\t\t
\t\t\t// Needed to force update of text bounds
\t\t\tthis.shape.redraw();
\t\t}
\t}
};

/**
 * Function: isHtmlRequired
 * 
 * Returns true if this handle should be rendered in HTML. This returns true if
 * the text node is in the graph container.
 */
mxHandle.prototype.isHtmlRequired = function()
{
\treturn this.state.text != null && this.state.text.node.parentNode == this.graph.container;
};

/**
 * Function: rotatePoint
 * 
 * Rotates the point by the given angle.
 */
mxHandle.prototype.rotatePoint = function(pt, alpha)
{
\tvar bounds = this.state.getCellBounds();
\tvar cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
\tvar cos = Math.cos(alpha);
\tvar sin = Math.sin(alpha); 

\treturn mxUtils.getRotatedPoint(pt, cos, sin, cx);
};

/**
 * Function: flipPoint
 * 
 * Flips the given point vertically and/or horizontally.
 */
mxHandle.prototype.flipPoint = function(pt)
{
\tif (this.state.shape != null)
\t{
\t\tvar bounds = this.state.getCellBounds();
\t\t
\t\tif (this.state.shape.flipH)
\t\t{
\t\t\tpt.x = 2 * bounds.x + bounds.width - pt.x;
\t\t}
\t\t
\t\tif (this.state.shape.flipV)
\t\t{
\t\t\tpt.y = 2 * bounds.y + bounds.height - pt.y;
\t\t}
\t}
\t
\treturn pt;
};

/**
 * Function: snapPoint
 * 
 * Snaps the given point to the grid if ignore is false. This modifies
 * the given point in-place and also returns it.
 */
mxHandle.prototype.snapPoint = function(pt, ignore)
{
\tif (!ignore)
\t{
\t\tpt.x = this.graph.snap(pt.x);
\t\tpt.y = this.graph.snap(pt.y);
\t}
\t
\treturn pt;
};

/**
 * Function: setVisible
 * 
 * Shows or hides this handle.
 */
mxHandle.prototype.setVisible = function(visible)
{
\tif (this.shape != null && this.shape.node != null)
\t{
\t\tthis.shape.node.style.display = (visible) ? '' : 'none';
\t}
};

/**
 * Function: reset
 * 
 * Resets the state of this handle by setting its visibility to true.
 */
mxHandle.prototype.reset = function()
{
\tthis.setVisible(true);
\tthis.state.style = this.graph.getCellStyle(this.state.cell);
\tthis.positionChanged();
};

/**
 * Function: destroy
 * 
 * Destroys this handle.
 */
mxHandle.prototype.destroy = function()
{
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxVertexHandler
 * 
 * Event handler for resizing cells. This handler is automatically created in
 * <mxGraph.createHandler>.
 * 
 * Constructor: mxVertexHandler
 * 
 * Constructs an event handler that allows to resize vertices
 * and groups.
 * 
 * Parameters:
 * 
 * state - <mxCellState> of the cell to be resized.
 */
function mxVertexHandler(state)
{
\tif (state != null)
\t{
\t\tthis.state = state;
\t\tthis.init();
\t\t
\t\t// Handles escape keystrokes
\t\tthis.escapeHandler = mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tif (this.livePreview && this.index != null)
\t\t\t{
\t\t\t\t// Redraws the live preview
\t\t\t\tthis.state.view.graph.cellRenderer.redraw(this.state, true);
\t\t\t\t
\t\t\t\t// Redraws connected edges
\t\t\t\tthis.state.view.invalidate(this.state.cell);
\t\t\t\tthis.state.invalid = false;
\t\t\t\tthis.state.view.validate();
\t\t\t}
\t\t\t
\t\t\tthis.reset();
\t\t});
\t\t
\t\tthis.state.view.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
\t}
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxVertexHandler.prototype.graph = null;

/**
 * Variable: state
 * 
 * Reference to the <mxCellState> being modified.
 */
mxVertexHandler.prototype.state = null;

/**
 * Variable: singleSizer
 * 
 * Specifies if only one sizer handle at the bottom, right corner should be
 * used. Default is false.
 */
mxVertexHandler.prototype.singleSizer = false;

/**
 * Variable: index
 * 
 * Holds the index of the current handle.
 */
mxVertexHandler.prototype.index = null;

/**
 * Variable: allowHandleBoundsCheck
 * 
 * Specifies if the bounds of handles should be used for hit-detection in IE or
 * if <tolerance> > 0. Default is true.
 */
mxVertexHandler.prototype.allowHandleBoundsCheck = true;

/**
 * Variable: handleImage
 * 
 * Optional <mxImage> to be used as handles. Default is null.
 */
mxVertexHandler.prototype.handleImage = null;

/**
 * Variable: handlesVisible
 * 
 * If handles are currently visible.
 */
mxVertexHandler.prototype.handlesVisible = true;

/**
 * Variable: tolerance
 * 
 * Optional tolerance for hit-detection in <getHandleForEvent>. Default is 0.
 */
mxVertexHandler.prototype.tolerance = 0;

/**
 * Variable: rotationEnabled
 * 
 * Specifies if a rotation handle should be visible. Default is false.
 */
mxVertexHandler.prototype.rotationEnabled = false;

/**
 * Variable: parentHighlightEnabled
 * 
 * Specifies if the parent should be highlighted if a child cell is selected.
 * Default is false.
 */
mxVertexHandler.prototype.parentHighlightEnabled = false;

/**
 * Variable: rotationRaster
 * 
 * Specifies if rotation steps should be \"rasterized\" depening on the distance
 * to the handle. Default is true.
 */
mxVertexHandler.prototype.rotationRaster = true;

/**
 * Variable: rotationCursor
 * 
 * Specifies the cursor for the rotation handle. Default is 'crosshair'.
 */
mxVertexHandler.prototype.rotationCursor = 'crosshair';

/**
 * Variable: livePreview
 * 
 * Specifies if resize should change the cell in-place. This is an experimental
 * feature for non-touch devices. Default is false.
 */
mxVertexHandler.prototype.livePreview = false;

/**
 * Variable: movePreviewToFront
 * 
 * Specifies if the live preview should be moved to the front.
 */
mxVertexHandler.prototype.movePreviewToFront = false;

/**
 * Variable: manageSizers
 * 
 * Specifies if sizers should be hidden and spaced if the vertex is small.
 * Default is false.
 */
mxVertexHandler.prototype.manageSizers = false;

/**
 * Variable: constrainGroupByChildren
 * 
 * Specifies if the size of groups should be constrained by the children.
 * Default is false.
 */
mxVertexHandler.prototype.constrainGroupByChildren = false;

/**
 * Variable: rotationHandleVSpacing
 * 
 * Vertical spacing for rotation icon. Default is -16.
 */
mxVertexHandler.prototype.rotationHandleVSpacing = -16;

/**
 * Variable: horizontalOffset
 * 
 * The horizontal offset for the handles. This is updated in <redrawHandles>
 * if <manageSizers> is true and the sizers are offset horizontally.
 */
mxVertexHandler.prototype.horizontalOffset = 0;

/**
 * Variable: verticalOffset
 * 
 * The horizontal offset for the handles. This is updated in <redrawHandles>
 * if <manageSizers> is true and the sizers are offset vertically.
 */
mxVertexHandler.prototype.verticalOffset = 0;

/**
 * Function: init
 * 
 * Initializes the shapes required for this vertex handler.
 */
mxVertexHandler.prototype.init = function()
{
\tthis.graph = this.state.view.graph;
\tthis.selectionBounds = this.getSelectionBounds(this.state);
\tthis.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y, this.selectionBounds.width, this.selectionBounds.height);
\tthis.selectionBorder = this.createSelectionShape(this.bounds);
\t// VML dialect required here for event transparency in IE
\tthis.selectionBorder.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\tthis.selectionBorder.pointerEvents = false;
\tthis.selectionBorder.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\tthis.selectionBorder.init(this.graph.getView().getOverlayPane());
\tmxEvent.redirectMouseEvents(this.selectionBorder.node, this.graph, this.state);
\t
\tif (this.graph.isCellMovable(this.state.cell))
\t{
\t\tthis.selectionBorder.setCursor(mxConstants.CURSOR_MOVABLE_VERTEX);
\t}

\t// Adds the sizer handles
\tif (mxGraphHandler.prototype.maxCells <= 0 || this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells)
\t{
\t\tvar resizable = this.graph.isCellResizable(this.state.cell);
\t\tthis.sizers = [];

\t\tif (resizable || (this.graph.isLabelMovable(this.state.cell) &&
\t\t\tthis.state.width >= 2 && this.state.height >= 2))
\t\t{
\t\t\tvar i = 0;

\t\t\tif (resizable)
\t\t\t{
\t\t\t\tif (!this.singleSizer)
\t\t\t\t{
\t\t\t\t\tthis.sizers.push(this.createSizer('nw-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('n-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('ne-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('w-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('e-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('sw-resize', i++));
\t\t\t\t\tthis.sizers.push(this.createSizer('s-resize', i++));
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.sizers.push(this.createSizer('se-resize', i++));
\t\t\t}
\t\t\t
\t\t\tvar geo = this.graph.model.getGeometry(this.state.cell);
\t\t\t
\t\t\tif (geo != null && !geo.relative && !this.graph.isSwimlane(this.state.cell) &&
\t\t\t\tthis.graph.isLabelMovable(this.state.cell))
\t\t\t{
\t\t\t\t// Marks this as the label handle for getHandleForEvent
\t\t\t\tthis.labelShape = this.createSizer(mxConstants.CURSOR_LABEL_HANDLE, mxEvent.LABEL_HANDLE,
\t\t\t\t\tmxConstants.LABEL_HANDLE_SIZE, mxConstants.LABEL_HANDLE_FILLCOLOR);
\t\t\t\tthis.sizers.push(this.labelShape);
\t\t\t}
\t\t}
\t\telse if (this.graph.isCellMovable(this.state.cell) && !this.graph.isCellResizable(this.state.cell) &&
\t\t\tthis.state.width < 2 && this.state.height < 2)
\t\t{
\t\t\tthis.labelShape = this.createSizer(mxConstants.CURSOR_MOVABLE_VERTEX,
\t\t\t\tmxEvent.LABEL_HANDLE, null, mxConstants.LABEL_HANDLE_FILLCOLOR);
\t\t\tthis.sizers.push(this.labelShape);
\t\t}
\t}
\t
\t// Adds the rotation handler
\tif (this.isRotationHandleVisible())
\t{
\t\tthis.rotationShape = this.createSizer(this.rotationCursor, mxEvent.ROTATION_HANDLE,
\t\t\tmxConstants.HANDLE_SIZE + 3, mxConstants.HANDLE_FILLCOLOR);
\t\tthis.sizers.push(this.rotationShape);
\t}

\tthis.customHandles = this.createCustomHandles();
\tthis.redraw();
\t
\tif (this.constrainGroupByChildren)
\t{
\t\tthis.updateMinBounds();
\t}
};

/**
 * Function: isRotationHandleVisible
 * 
 * Returns true if the rotation handle should be showing.
 */
mxVertexHandler.prototype.isRotationHandleVisible = function()
{
\treturn this.graph.isEnabled() && this.rotationEnabled && this.graph.isCellRotatable(this.state.cell) &&
\t\t(mxGraphHandler.prototype.maxCells <= 0 || this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells);
};

/**
 * Function: isConstrainedEvent
 * 
 * Returns true if the aspect ratio if the cell should be maintained.
 */
mxVertexHandler.prototype.isConstrainedEvent = function(me)
{
\treturn mxEvent.isShiftDown(me.getEvent()) || this.state.style[mxConstants.STYLE_ASPECT] == 'fixed';
};

/**
 * Function: isCenteredEvent
 * 
 * Returns true if the center of the vertex should be maintained during the resize.
 */
mxVertexHandler.prototype.isCenteredEvent = function(state, me)
{
\treturn false;
};

/**
 * Function: createCustomHandles
 * 
 * Returns an array of custom handles. This implementation returns null.
 */
mxVertexHandler.prototype.createCustomHandles = function()
{
\treturn null;
};

/**
 * Function: updateMinBounds
 * 
 * Initializes the shapes required for this vertex handler.
 */
mxVertexHandler.prototype.updateMinBounds = function()
{
\tvar children = this.graph.getChildCells(this.state.cell);
\t
\tif (children.length > 0)
\t{
\t\tthis.minBounds = this.graph.view.getBounds(children);
\t\t
\t\tif (this.minBounds != null)
\t\t{
\t\t\tvar s = this.state.view.scale;
\t\t\tvar t = this.state.view.translate;

\t\t\tthis.minBounds.x -= this.state.x;
\t\t\tthis.minBounds.y -= this.state.y;
\t\t\tthis.minBounds.x /= s;
\t\t\tthis.minBounds.y /= s;
\t\t\tthis.minBounds.width /= s;
\t\t\tthis.minBounds.height /= s;
\t\t\tthis.x0 = this.state.x / s - t.x;
\t\t\tthis.y0 = this.state.y / s - t.y;
\t\t}
\t}
};

/**
 * Function: getSelectionBounds
 * 
 * Returns the mxRectangle that defines the bounds of the selection
 * border.
 */
mxVertexHandler.prototype.getSelectionBounds = function(state)
{
\treturn new mxRectangle(Math.round(state.x), Math.round(state.y), Math.round(state.width), Math.round(state.height));
};

/**
 * Function: createParentHighlightShape
 * 
 * Creates the shape used to draw the selection border.
 */
mxVertexHandler.prototype.createParentHighlightShape = function(bounds)
{
\treturn this.createSelectionShape(bounds);
};

/**
 * Function: createSelectionShape
 * 
 * Creates the shape used to draw the selection border.
 */
mxVertexHandler.prototype.createSelectionShape = function(bounds)
{
\tvar shape = new mxRectangleShape(
\t\tmxRectangle.fromRectangle(bounds),
\t\tnull, this.getSelectionColor());
\tshape.strokewidth = this.getSelectionStrokeWidth();
\tshape.isDashed = this.isSelectionDashed();
\t
\treturn shape;
};

/**
 * Function: getSelectionColor
 * 
 * Returns <mxConstants.VERTEX_SELECTION_COLOR>.
 */
mxVertexHandler.prototype.getSelectionColor = function()
{
\treturn mxConstants.VERTEX_SELECTION_COLOR;
};

/**
 * Function: getSelectionStrokeWidth
 * 
 * Returns <mxConstants.VERTEX_SELECTION_STROKEWIDTH>.
 */
mxVertexHandler.prototype.getSelectionStrokeWidth = function()
{
\treturn mxConstants.VERTEX_SELECTION_STROKEWIDTH;
};

/**
 * Function: isSelectionDashed
 * 
 * Returns <mxConstants.VERTEX_SELECTION_DASHED>.
 */
mxVertexHandler.prototype.isSelectionDashed = function()
{
\treturn mxConstants.VERTEX_SELECTION_DASHED;
};

/**
 * Function: createSizer
 * 
 * Creates a sizer handle for the specified cursor and index and returns
 * the new <mxRectangleShape> that represents the handle.
 */
mxVertexHandler.prototype.createSizer = function(cursor, index, size, fillColor)
{
\tsize = size || mxConstants.HANDLE_SIZE;
\t
\tvar bounds = new mxRectangle(0, 0, size, size);
\tvar sizer = this.createSizerShape(bounds, index, fillColor);

\tif (sizer.isHtmlAllowed() && this.state.text != null && this.state.text.node.parentNode == this.graph.container)
\t{
\t\tsizer.bounds.height -= 1;
\t\tsizer.bounds.width -= 1;
\t\tsizer.dialect = mxConstants.DIALECT_STRICTHTML;
\t\tsizer.init(this.graph.container);
\t}
\telse
\t{
\t\tsizer.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\t\tmxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
\t\tsizer.init(this.graph.getView().getOverlayPane());
\t}

\tmxEvent.redirectMouseEvents(sizer.node, this.graph, this.state);
\t
\tif (this.graph.isEnabled())
\t{
\t\tsizer.setCursor(cursor);
\t}
\t
\tif (!this.isSizerVisible(index))
\t{
\t\tsizer.visible = false;
\t}
\t
\treturn sizer;
};

/**
 * Function: isSizerVisible
 * 
 * Returns true if the sizer for the given index is visible.
 * This returns true for all given indices.
 */
mxVertexHandler.prototype.isSizerVisible = function(index)
{
\treturn true;
};

/**
 * Function: createSizerShape
 * 
 * Creates the shape used for the sizer handle for the specified bounds an
 * index. Only images and rectangles should be returned if support for HTML
 * labels with not foreign objects is required.
 */
mxVertexHandler.prototype.createSizerShape = function(bounds, index, fillColor)
{
\tif (this.handleImage != null)
\t{
\t\tbounds = new mxRectangle(bounds.x, bounds.y, this.handleImage.width, this.handleImage.height);
\t\tvar shape = new mxImageShape(bounds, this.handleImage.src);
\t\t
\t\t// Allows HTML rendering of the images
\t\tshape.preserveImageAspect = false;

\t\treturn shape;
\t}
\telse if (index == mxEvent.ROTATION_HANDLE)
\t{
\t\treturn new mxEllipse(bounds, fillColor || mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
\t}
\telse
\t{
\t\treturn new mxRectangleShape(bounds, fillColor || mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
\t}
};

/**
 * Function: createBounds
 * 
 * Helper method to create an <mxRectangle> around the given centerpoint
 * with a width and height of 2*s or 6, if no s is given.
 */
mxVertexHandler.prototype.moveSizerTo = function(shape, x, y)
{
\tif (shape != null)
\t{
\t\tshape.bounds.x = Math.floor(x - shape.bounds.width / 2);
\t\tshape.bounds.y = Math.floor(y - shape.bounds.height / 2);
\t\t
\t\t// Fixes visible inactive handles in VML
\t\tif (shape.node != null && shape.node.style.display != 'none')
\t\t{
\t\t\tshape.redraw();
\t\t}
\t}
};

/**
 * Function: getHandleForEvent
 * 
 * Returns the index of the handle for the given event. This returns the index
 * of the sizer from where the event originated or <mxEvent.LABEL_INDEX>.
 */
mxVertexHandler.prototype.getHandleForEvent = function(me)
{
\t// Connection highlight may consume events before they reach sizer handle
\tvar tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.tolerance : 1;
\tvar hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
\t\tnew mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;

\tvar checkShape = mxUtils.bind(this, function(shape)
\t{
\t\tvar st = (shape != null && shape.constructor != mxImageShape &&
\t\t\tthis.allowHandleBoundsCheck) ? shape.strokewidth + shape.svgStrokeTolerance : null;
\t\tvar real = (st != null) ? new mxRectangle(me.getGraphX() - Math.floor(st / 2),
\t\t\tme.getGraphY() - Math.floor(st / 2), st, st) : hit;

\t\treturn shape != null && (me.isSource(shape) || (real != null && mxUtils.intersects(shape.bounds, real) &&
\t\t\tshape.node.style.display != 'none' && shape.node.style.visibility != 'hidden'));
\t});
\t
\tif (checkShape(this.rotationShape))
\t{
\t\treturn mxEvent.ROTATION_HANDLE;
\t}
\telse if (checkShape(this.labelShape))
\t{
\t\treturn mxEvent.LABEL_HANDLE;
\t}

\tif (this.sizers != null)
\t{
\t\tfor (var i = 0; i < this.sizers.length; i++)
\t\t{
\t\t\tif (checkShape(this.sizers[i]))
\t\t\t{
\t\t\t\treturn i;
\t\t\t}
\t\t}
\t}

\tif (this.customHandles != null && this.isCustomHandleEvent(me))
\t{
\t\t// Inverse loop order to match display order
\t\tfor (var i = this.customHandles.length - 1; i >= 0; i--)
\t\t{
\t\t\tif (checkShape(this.customHandles[i].shape))
\t\t\t{
\t\t\t\t// LATER: Return reference to active shape
\t\t\t\treturn mxEvent.CUSTOM_HANDLE - i;
\t\t\t}
\t\t}
\t}

\treturn null;
};

/**
 * Function: isCustomHandleEvent
 * 
 * Returns true if the given event allows custom handles to be changed. This
 * implementation returns true.
 */
mxVertexHandler.prototype.isCustomHandleEvent = function(me)
{
\treturn true;
};

/**
 * Function: mouseDown
 * 
 * Handles the event if a handle has been clicked. By consuming the
 * event all subsequent events of the gesture are redirected to this
 * handler.
 */
mxVertexHandler.prototype.mouseDown = function(sender, me)
{
\tif (!me.isConsumed() && this.graph.isEnabled())
\t{
\t\tvar handle = this.getHandleForEvent(me);

\t\tif (handle != null)
\t\t{
\t\t\tthis.start(me.getGraphX(), me.getGraphY(), handle);
\t\t\tme.consume();
\t\t}
\t}
};

/**
 * Function: isLivePreviewBorder
 * 
 * Called if <livePreview> is enabled to check if a border should be painted.
 * This implementation returns true if the shape is transparent.
 */
mxVertexHandler.prototype.isLivePreviewBorder = function()
{
\treturn this.state.shape != null && this.state.shape.fill == null && this.state.shape.stroke == null;
};

/**
 * Function: start
 * 
 * Starts the handling of the mouse gesture.
 */
mxVertexHandler.prototype.start = function(x, y, index)
{
\tif (this.selectionBorder != null)
\t{
\t\tthis.livePreviewActive = this.livePreview && this.graph.model.getChildCount(this.state.cell) == 0;
\t\tthis.inTolerance = true;
\t\tthis.childOffsetX = 0;
\t\tthis.childOffsetY = 0;
\t\tthis.index = index;
\t\tthis.startX = x;
\t\tthis.startY = y;
\t\t
\t\tif (this.index <= mxEvent.CUSTOM_HANDLE && this.isGhostPreview())
\t\t{
\t\t\tthis.ghostPreview = this.createGhostPreview();
\t\t}
\t\telse
\t\t{
\t\t\t// Saves reference to parent state
\t\t\tvar model = this.state.view.graph.model;
\t\t\tvar parent = model.getParent(this.state.cell);
\t\t\t
\t\t\tif (this.state.view.currentRoot != parent && (model.isVertex(parent) || model.isEdge(parent)))
\t\t\t{
\t\t\t\tthis.parentState = this.state.view.graph.view.getState(parent);
\t\t\t}
\t\t\t
\t\t\t// Creates a preview that can be on top of any HTML label
\t\t\tthis.selectionBorder.node.style.display = (index == mxEvent.ROTATION_HANDLE) ? 'inline' : 'none';
\t\t\t
\t\t\t// Creates the border that represents the new bounds
\t\t\tif (!this.livePreviewActive || this.isLivePreviewBorder())
\t\t\t{
\t\t\t\tthis.preview = this.createSelectionShape(this.bounds);
\t\t\t\t
\t\t\t\tif (!(mxClient.IS_SVG && Number(this.state.style[mxConstants.STYLE_ROTATION] || '0') != 0) &&
\t\t\t\t\tthis.state.text != null && this.state.text.node.parentNode == this.graph.container)
\t\t\t\t{
\t\t\t\t\tthis.preview.dialect = mxConstants.DIALECT_STRICTHTML;
\t\t\t\t\tthis.preview.init(this.graph.container);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.preview.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\t\t\t\t\tmxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\t\t\t\t\tthis.preview.init(this.graph.view.getOverlayPane());
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (index == mxEvent.ROTATION_HANDLE)
\t\t\t{
\t\t\t\t// With the rotation handle in a corner, need the angle and distance
\t\t\t\tvar pos = this.getRotationHandlePosition();
\t\t\t\t
\t\t\t\tvar dx = pos.x - this.state.getCenterX();
\t\t\t\tvar dy = pos.y - this.state.getCenterY();
\t\t\t\t
\t\t\t\tthis.startAngle = (dx != 0) ? Math.atan(dy / dx) * 180 / Math.PI + 90 : 0;
\t\t\t\tthis.startDist = Math.sqrt(dx * dx + dy * dy);
\t\t\t}
\t
\t\t\t// Prepares the handles for live preview
\t\t\tif (this.livePreviewActive)
\t\t\t{
\t\t\t\tthis.hideSizers();
\t\t\t\t
\t\t\t\tif (index == mxEvent.ROTATION_HANDLE)
\t\t\t\t{
\t\t\t\t\tthis.rotationShape.node.style.display = '';
\t\t\t\t}
\t\t\t\telse if (index == mxEvent.LABEL_HANDLE)
\t\t\t\t{
\t\t\t\t\tthis.labelShape.node.style.display = '';
\t\t\t\t}
\t\t\t\telse if (this.sizers != null && this.sizers[index] != null)
\t\t\t\t{
\t\t\t\t\tthis.sizers[index].node.style.display = '';
\t\t\t\t}
\t\t\t\telse if (index <= mxEvent.CUSTOM_HANDLE && this.customHandles != null)
\t\t\t\t{
\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index].setVisible(true);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Gets the array of connected edge handlers for redrawing
\t\t\t\tvar edges = this.graph.getEdges(this.state.cell);
\t\t\t\tthis.edgeHandlers = [];
\t\t\t\t
\t\t\t\tfor (var i = 0; i < edges.length; i++)
\t\t\t\t{
\t\t\t\t\tvar handler = this.graph.selectionCellsHandler.getHandler(edges[i]);
\t\t\t\t\t
\t\t\t\t\tif (handler != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.edgeHandlers.push(handler);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: createGhostPreview
 * 
 * Starts the handling of the mouse gesture.
 */
mxVertexHandler.prototype.createGhostPreview = function()
{
\tvar shape = this.graph.cellRenderer.createShape(this.state);
\tshape.init(this.graph.view.getOverlayPane());
\tshape.scale = this.state.view.scale;
\tshape.bounds = this.bounds;
\tshape.outline = true;
\t
\treturn shape;
};

/**
 * Function: hideHandles
 * 
 * Shortcut to <hideSizers>.
 */
mxVertexHandler.prototype.setHandlesVisible = function(visible)
{
\tthis.handlesVisible = visible;
\t
\tif (this.sizers != null)
\t{
\t\tfor (var i = 0; i < this.sizers.length; i++)
\t\t{
\t\t\tthis.sizers[i].node.style.display = (visible) ? '' : 'none';
\t\t}
\t}

\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tthis.customHandles[i].setVisible(visible);
\t\t}
\t}
};

/**
 * Function: hideSizers
 * 
 * Hides all sizers except.
 * 
 * Starts the handling of the mouse gesture.
 */
mxVertexHandler.prototype.hideSizers = function()
{
\tthis.setHandlesVisible(false);
};

/**
 * Function: checkTolerance
 * 
 * Checks if the coordinates for the given event are within the
 * <mxGraph.tolerance>. If the event is a mouse event then the tolerance is
 * ignored.
 */
mxVertexHandler.prototype.checkTolerance = function(me)
{
\tif (this.inTolerance && this.startX != null && this.startY != null)
\t{
\t\tif (mxEvent.isMouseEvent(me.getEvent()) ||
\t\t\tMath.abs(me.getGraphX() - this.startX) > this.graph.tolerance ||
\t\t\tMath.abs(me.getGraphY() - this.startY) > this.graph.tolerance)
\t\t{
\t\t\tthis.inTolerance = false;
\t\t}
\t}
};

/**
 * Function: updateHint
 * 
 * Hook for subclassers do show details while the handler is active.
 */
mxVertexHandler.prototype.updateHint = function(me) { };

/**
 * Function: removeHint
 * 
 * Hooks for subclassers to hide details when the handler gets inactive.
 */
mxVertexHandler.prototype.removeHint = function() { };

/**
 * Function: roundAngle
 * 
 * Hook for rounding the angle. This uses Math.round.
 */
mxVertexHandler.prototype.roundAngle = function(angle)
{
\treturn Math.round(angle * 10) / 10;
};

/**
 * Function: roundLength
 * 
 * Hook for rounding the unscaled width or height. This uses Math.round.
 */
mxVertexHandler.prototype.roundLength = function(length)
{
\treturn Math.round(length * 100) / 100;
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the preview.
 */
mxVertexHandler.prototype.mouseMove = function(sender, me)
{
\tif (!me.isConsumed() && this.index != null)
\t{
\t\t// Checks tolerance for ignoring single clicks
\t\tthis.checkTolerance(me);

\t\tif (!this.inTolerance)
\t\t{
\t\t\tif (this.index <= mxEvent.CUSTOM_HANDLE)
\t\t\t{
\t\t\t\tif (this.customHandles != null)
\t\t\t\t{
\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - this.index].processEvent(me);
\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - this.index].active = true;
\t\t\t\t\t
\t\t\t\t\tif (this.ghostPreview != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.ghostPreview.apply(this.state);
\t\t\t\t\t\tthis.ghostPreview.strokewidth = this.getSelectionStrokeWidth() /
\t\t\t\t\t\t\tthis.ghostPreview.scale / this.ghostPreview.scale;
\t\t\t\t\t\tthis.ghostPreview.isDashed = this.isSelectionDashed();
\t\t\t\t\t\tthis.ghostPreview.stroke = this.getSelectionColor();
\t\t\t\t\t\tthis.ghostPreview.redraw();
\t\t\t\t\t\t
\t\t\t\t\t\tif (this.selectionBounds != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.selectionBorder.node.style.display = 'none';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tif (this.movePreviewToFront)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.moveToFront();
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - this.index].positionChanged();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (this.index == mxEvent.LABEL_HANDLE)
\t\t\t{
\t\t\t\tthis.moveLabel(me);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (this.index == mxEvent.ROTATION_HANDLE)
\t\t\t\t{
\t\t\t\t\tthis.rotateVertex(me);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.resizeVertex(me);
\t\t\t\t}

\t\t\t\tthis.updateHint(me);
\t\t\t}
\t\t}
\t\t
\t\tme.consume();
\t}
\t// Workaround for disabling the connect highlight when over handle
\telse if (!this.graph.isMouseDown && this.getHandleForEvent(me) != null)
\t{
\t\tme.consume(false);
\t}
};

/**
 * Function: isGhostPreview
 * 
 * Returns true if a ghost preview should be used for custom handles.
 */
mxVertexHandler.prototype.isGhostPreview = function()
{
\treturn this.state.view.graph.model.getChildCount(this.state.cell) > 0;
};

/**
 * Function: moveLabel
 * 
 * Moves the label.
 */
mxVertexHandler.prototype.moveLabel = function(me)
{
\tvar point = new mxPoint(me.getGraphX(), me.getGraphY());
\tvar tr = this.graph.view.translate;
\tvar scale = this.graph.view.scale;
\t
\tif (this.graph.isGridEnabledEvent(me.getEvent()))
\t{
\t\tpoint.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale;
\t\tpoint.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale;
\t}

\tvar index = (this.rotationShape != null) ? this.sizers.length - 2 : this.sizers.length - 1;
\tthis.moveSizerTo(this.sizers[index], point.x, point.y);
};

/**
 * Function: rotateVertex
 * 
 * Rotates the vertex.
 */
mxVertexHandler.prototype.rotateVertex = function(me)
{
\tvar point = new mxPoint(me.getGraphX(), me.getGraphY());
\tvar dx = this.state.x + this.state.width / 2 - point.x;
\tvar dy = this.state.y + this.state.height / 2 - point.y;
\tthis.currentAlpha = (dx != 0) ? Math.atan(dy / dx) * 180 / Math.PI + 90 : ((dy < 0) ? 180 : 0);
\t
\tif (dx > 0)
\t{
\t\tthis.currentAlpha -= 180;
\t}
\t
\tthis.currentAlpha -= this.startAngle;
\t
\t// Rotation raster
\tif (this.rotationRaster && this.graph.isGridEnabledEvent(me.getEvent()))
\t{
\t\tvar dx = point.x - this.state.getCenterX();
\t\tvar dy = point.y - this.state.getCenterY();
\t\tvar dist = Math.sqrt(dx * dx + dy * dy);
\t\t
\t\tif (dist - this.startDist < 2)
\t\t{
\t\t\traster = 15;
\t\t}
\t\telse if (dist - this.startDist < 25)
\t\t{
\t\t\traster = 5;
\t\t}
\t\telse
\t\t{
\t\t\traster = 1;
\t\t}
\t\t
\t\tthis.currentAlpha = Math.round(this.currentAlpha / raster) * raster;
\t}
\telse
\t{
\t\tthis.currentAlpha = this.roundAngle(this.currentAlpha);
\t}

\tthis.selectionBorder.rotation = this.currentAlpha;
\tthis.selectionBorder.redraw();
\t\t\t\t\t
\tif (this.livePreviewActive)
\t{
\t\tthis.redrawHandles();
\t}
};

/**
 * Function: resizeVertex
 * 
 * Risizes the vertex.
 */
mxVertexHandler.prototype.resizeVertex = function(me)
{
\tvar ct = new mxPoint(this.state.getCenterX(), this.state.getCenterY());
\tvar alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\tvar point = new mxPoint(me.getGraphX(), me.getGraphY());
\tvar tr = this.graph.view.translate;
\tvar scale = this.graph.view.scale;
\tvar cos = Math.cos(-alpha);
\tvar sin = Math.sin(-alpha);
\t
\tvar dx = point.x - this.startX;
\tvar dy = point.y - this.startY;

\t// Rotates vector for mouse gesture
\tvar tx = cos * dx - sin * dy;
\tvar ty = sin * dx + cos * dy;
\t
\tdx = tx;
\tdy = ty;

\tvar geo = this.graph.getCellGeometry(this.state.cell);
\tthis.unscaledBounds = this.union(geo, dx / scale, dy / scale, this.index,
\t\tthis.graph.isGridEnabledEvent(me.getEvent()), 1,
\t\tnew mxPoint(0, 0), this.isConstrainedEvent(me),
\t\tthis.isCenteredEvent(this.state, me));
\t
\t// Keeps vertex within maximum graph or parent bounds
\tif (!geo.relative)
\t{
\t\tvar max = this.graph.getMaximumGraphBounds();
\t\t
\t\t// Handles child cells
\t\tif (max != null && this.parentState != null)
\t\t{
\t\t\tmax = mxRectangle.fromRectangle(max);
\t\t\t
\t\t\tmax.x -= (this.parentState.x - tr.x * scale) / scale;
\t\t\tmax.y -= (this.parentState.y - tr.y * scale) / scale;
\t\t}
\t\t
\t\tif (this.graph.isConstrainChild(this.state.cell))
\t\t{
\t\t\tvar tmp = this.graph.getCellContainmentArea(this.state.cell);
\t\t\t
\t\t\tif (tmp != null)
\t\t\t{
\t\t\t\tvar overlap = this.graph.getOverlap(this.state.cell);
\t\t\t\t
\t\t\t\tif (overlap > 0)
\t\t\t\t{
\t\t\t\t\ttmp = mxRectangle.fromRectangle(tmp);
\t\t\t\t\t
\t\t\t\t\ttmp.x -= tmp.width * overlap;
\t\t\t\t\ttmp.y -= tmp.height * overlap;
\t\t\t\t\ttmp.width += 2 * tmp.width * overlap;
\t\t\t\t\ttmp.height += 2 * tmp.height * overlap;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (max == null)
\t\t\t\t{
\t\t\t\t\tmax = tmp;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tmax = mxRectangle.fromRectangle(max);
\t\t\t\t\tmax.intersect(tmp);
\t\t\t\t}
\t\t\t}
\t\t}
\t
\t\tif (max != null)
\t\t{
\t\t\tif (this.unscaledBounds.x < max.x)
\t\t\t{
\t\t\t\tthis.unscaledBounds.width -= max.x - this.unscaledBounds.x;
\t\t\t\tthis.unscaledBounds.x = max.x;
\t\t\t}
\t\t\t
\t\t\tif (this.unscaledBounds.y < max.y)
\t\t\t{
\t\t\t\tthis.unscaledBounds.height -= max.y - this.unscaledBounds.y;
\t\t\t\tthis.unscaledBounds.y = max.y;
\t\t\t}
\t\t\t
\t\t\tif (this.unscaledBounds.x + this.unscaledBounds.width > max.x + max.width)
\t\t\t{
\t\t\t\tthis.unscaledBounds.width -= this.unscaledBounds.x +
\t\t\t\t\tthis.unscaledBounds.width - max.x - max.width;
\t\t\t}
\t\t\t
\t\t\tif (this.unscaledBounds.y + this.unscaledBounds.height > max.y + max.height)
\t\t\t{
\t\t\t\tthis.unscaledBounds.height -= this.unscaledBounds.y +
\t\t\t\t\tthis.unscaledBounds.height - max.y - max.height;
\t\t\t}
\t\t}
\t}
\t
\tvar old = this.bounds;
\tthis.bounds = new mxRectangle(((this.parentState != null) ? this.parentState.x : tr.x * scale) +
\t\t(this.unscaledBounds.x) * scale, ((this.parentState != null) ? this.parentState.y : tr.y * scale) +
\t\t(this.unscaledBounds.y) * scale, this.unscaledBounds.width * scale, this.unscaledBounds.height * scale);

\tif (geo.relative && this.parentState != null)
\t{
\t\tthis.bounds.x += this.state.x - this.parentState.x;
\t\tthis.bounds.y += this.state.y - this.parentState.y;
\t}

\tcos = Math.cos(alpha);
\tsin = Math.sin(alpha);
\t
\tvar c2 = new mxPoint(this.bounds.getCenterX(), this.bounds.getCenterY());

\tvar dx = c2.x - ct.x;
\tvar dy = c2.y - ct.y;
\t
\tvar dx2 = cos * dx - sin * dy;
\tvar dy2 = sin * dx + cos * dy;
\t
\tvar dx3 = dx2 - dx;
\tvar dy3 = dy2 - dy;
\t
\tvar dx4 = this.bounds.x - this.state.x;
\tvar dy4 = this.bounds.y - this.state.y;
\t
\tvar dx5 = cos * dx4 - sin * dy4;
\tvar dy5 = sin * dx4 + cos * dy4;
\t
\tthis.bounds.x += dx3;
\tthis.bounds.y += dy3;
\t
\t// Rounds unscaled bounds to int
\tthis.unscaledBounds.x = this.roundLength(this.unscaledBounds.x + dx3 / scale);
\tthis.unscaledBounds.y = this.roundLength(this.unscaledBounds.y + dy3 / scale);
\tthis.unscaledBounds.width = this.roundLength(this.unscaledBounds.width);
\tthis.unscaledBounds.height = this.roundLength(this.unscaledBounds.height);
\t
\t// Shifts the children according to parent offset
\tif (!this.graph.isCellCollapsed(this.state.cell) && (dx3 != 0 || dy3 != 0))
\t{
\t\tthis.childOffsetX = this.state.x - this.bounds.x + dx5;
\t\tthis.childOffsetY = this.state.y - this.bounds.y + dy5;
\t}
\telse
\t{
\t\tthis.childOffsetX = 0;
\t\tthis.childOffsetY = 0;
\t}
\t\t\t
\tif (!old.equals(this.bounds))
\t{\t
\t\tif (this.livePreviewActive)
\t\t{
\t\t\tthis.updateLivePreview(me);
\t\t}
\t\t
\t\tif (this.preview != null)
\t\t{
\t\t\tthis.drawPreview();
\t\t}
\t\telse
\t\t{
\t\t\tthis.updateParentHighlight();
\t\t}
\t}
};

/**
 * Function: updateLivePreview
 * 
 * Repaints the live preview.
 */
mxVertexHandler.prototype.updateLivePreview = function(me)
{
\t// TODO: Apply child offset to children in live preview
\tvar scale = this.graph.view.scale;
\tvar tr = this.graph.view.translate;
\t
\t// Saves current state
\tvar tempState = this.state.clone();

\t// Temporarily changes size and origin
\tthis.state.x = this.bounds.x;
\tthis.state.y = this.bounds.y;
\tthis.state.origin = new mxPoint(this.state.x / scale - tr.x, this.state.y / scale - tr.y);
\tthis.state.width = this.bounds.width;
\tthis.state.height = this.bounds.height;
\t
\t// Redraws cell and handles
\tvar off = this.state.absoluteOffset;
\toff = new mxPoint(off.x, off.y);

\t// Required to store and reset absolute offset for updating label position
\tthis.state.absoluteOffset.x = 0;
\tthis.state.absoluteOffset.y = 0;
\tvar geo = this.graph.getCellGeometry(this.state.cell);\t\t\t\t

\tif (geo != null)
\t{
\t\tvar offset = geo.offset || this.EMPTY_POINT;

\t\tif (offset != null && !geo.relative)
\t\t{
\t\t\tthis.state.absoluteOffset.x = this.state.view.scale * offset.x;
\t\t\tthis.state.absoluteOffset.y = this.state.view.scale * offset.y;
\t\t}
\t\t
\t\tthis.state.view.updateVertexLabelOffset(this.state);
\t}
\t
\t// Draws the live preview
\tthis.state.view.graph.cellRenderer.redraw(this.state, true);
\t
\t// Redraws connected edges TODO: Include child edges
\tthis.state.view.invalidate(this.state.cell);
\tthis.state.invalid = false;
\tthis.state.view.validate();
\tthis.redrawHandles();
\t
\t// Moves live preview to front
\tif (this.movePreviewToFront)
\t{
\t\tthis.moveToFront();
\t}
\t
\t// Hides folding icon
\tif (this.state.control != null && this.state.control.node != null)
\t{
\t\tthis.state.control.node.style.visibility = 'hidden';
\t}
\t
\t// Restores current state
\tthis.state.setState(tempState);
};

/**
 * Function: moveToFront
 * 
 * Handles the event by applying the changes to the geometry.
 */
mxVertexHandler.prototype.moveToFront = function()
{
\tif ((this.state.text != null && this.state.text.node != null &&
\t\tthis.state.text.node.nextSibling != null) ||
\t\t(this.state.shape != null && this.state.shape.node != null &&
\t\tthis.state.shape.node.nextSibling != null && (this.state.text == null ||
\t\tthis.state.shape.node.nextSibling != this.state.text.node)))
\t{
\t\tif (this.state.shape != null && this.state.shape.node != null)
\t\t{
\t\t\tthis.state.shape.node.parentNode.appendChild(this.state.shape.node);
\t\t}
\t\t
\t\tif (this.state.text != null && this.state.text.node != null)
\t\t{
\t\t\tthis.state.text.node.parentNode.appendChild(this.state.text.node);
\t\t}
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event by applying the changes to the geometry.
 */
mxVertexHandler.prototype.mouseUp = function(sender, me)
{
\tif (this.index != null && this.state != null)
\t{
\t\tvar point = new mxPoint(me.getGraphX(), me.getGraphY());
\t\tvar index = this.index;
\t\tthis.index = null;
\t
\t\tif (this.ghostPreview == null)
\t\t{
\t\t\t// Required to restore order in case of no change
\t\t\tthis.state.view.invalidate(this.state.cell, false, false);
\t\t\tthis.state.view.validate();
\t\t}
\t\t
\t\tthis.graph.getModel().beginUpdate();
\t\ttry
\t\t{
\t\t\tif (index <= mxEvent.CUSTOM_HANDLE)
\t\t\t{
\t\t\t\tif (this.customHandles != null)
\t\t\t\t{
\t\t\t\t\t// Creates style before changing cell state
\t\t\t\t\tvar style = this.state.view.graph.getCellStyle(this.state.cell);
\t\t\t\t\t
\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index].active = false;
\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index].execute(me);
\t\t\t\t\t
\t\t\t\t\t// Sets style and apply on shape to force repaint and
\t\t\t\t\t// check if execute has removed custom handles
\t\t\t\t\tif (this.customHandles != null &&
\t\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index] != null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.state.style = style;
\t\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index].positionChanged();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (index == mxEvent.ROTATION_HANDLE)
\t\t\t{
\t\t\t\tif (this.currentAlpha != null)
\t\t\t\t{
\t\t\t\t\tvar delta = this.currentAlpha - (this.state.style[mxConstants.STYLE_ROTATION] || 0);
\t\t\t\t\t
\t\t\t\t\tif (delta != 0)
\t\t\t\t\t{
\t\t\t\t\t\tthis.rotateCell(this.state.cell, delta);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.rotateClick();
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tvar gridEnabled = this.graph.isGridEnabledEvent(me.getEvent());
\t\t\t\tvar alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\t\t\tvar cos = Math.cos(-alpha);
\t\t\t\tvar sin = Math.sin(-alpha);
\t\t\t\t
\t\t\t\tvar dx = point.x - this.startX;
\t\t\t\tvar dy = point.y - this.startY;
\t\t\t\t
\t\t\t\t// Rotates vector for mouse gesture
\t\t\t\tvar tx = cos * dx - sin * dy;
\t\t\t\tvar ty = sin * dx + cos * dy;
\t\t\t\t
\t\t\t\tdx = tx;
\t\t\t\tdy = ty;
\t\t\t\t
\t\t\t\tvar s = this.graph.view.scale;
\t\t\t\tvar recurse = this.isRecursiveResize(this.state, me);
\t\t\t\tthis.resizeCell(this.state.cell, this.roundLength(dx / s), this.roundLength(dy / s),
\t\t\t\t\tindex, gridEnabled, this.isConstrainedEvent(me), recurse);
\t\t\t}
\t\t}
\t\tfinally
\t\t{
\t\t\tthis.graph.getModel().endUpdate();
\t\t}

\t\tme.consume();
\t\tthis.reset();
\t\tthis.redrawHandles();
\t}
};

/**
 * Function: isRecursiveResize
 * 
 * Returns the recursiveResize of the give state.
 * 
 * Parameters:
 * 
 * state - the given <mxCellState>. This implementation takes 
 * the value of this state.
 * me - the mouse event.
 */
mxVertexHandler.prototype.isRecursiveResize = function(state, me)
{
\treturn this.graph.isRecursiveResize(this.state);
};

/**
 * Function: rotateClick
 * 
 * Hook for subclassers to implement a single click on the rotation handle.
 * This code is executed as part of the model transaction. This implementation
 * is empty.
 */
mxVertexHandler.prototype.rotateClick = function() { };

/**
 * Function: rotateCell
 * 
 * Rotates the given cell and its children by the given angle in degrees.
 * 
 * Parameters:
 * 
 * cell - <mxCell> to be rotated.
 * angle - Angle in degrees.
 */
mxVertexHandler.prototype.rotateCell = function(cell, angle, parent)
{
\tif (angle != 0)
\t{
\t\tvar model = this.graph.getModel();

\t\tif (model.isVertex(cell) || model.isEdge(cell))
\t\t{
\t\t\tif (!model.isEdge(cell))
\t\t\t{
\t\t\t\tvar style = this.graph.getCurrentCellStyle(cell);
\t\t\t\tvar total = (style[mxConstants.STYLE_ROTATION] || 0) + angle;
\t\t\t\tthis.graph.setCellStyles(mxConstants.STYLE_ROTATION, total, [cell]);
\t\t\t}
\t\t\t
\t\t\tvar geo = this.graph.getCellGeometry(cell);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tvar pgeo = this.graph.getCellGeometry(parent);
\t\t\t\t
\t\t\t\tif (pgeo != null && !model.isEdge(parent))
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\tgeo.rotate(angle, new mxPoint(pgeo.width / 2, pgeo.height / 2));
\t\t\t\t\tmodel.setGeometry(cell, geo);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif ((model.isVertex(cell) && !geo.relative) || model.isEdge(cell))
\t\t\t\t{
\t\t\t\t\t// Recursive rotation
\t\t\t\t\tvar childCount = model.getChildCount(cell);
\t\t\t\t\t
\t\t\t\t\tfor (var i = 0; i < childCount; i++)
\t\t\t\t\t{
\t\t\t\t\t\tthis.rotateCell(model.getChildAt(cell, i), angle, cell);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxVertexHandler.prototype.reset = function()
{
\tif (this.sizers != null && this.index != null && this.sizers[this.index] != null &&
\t\tthis.sizers[this.index].node.style.display == 'none')
\t{
\t\tthis.sizers[this.index].node.style.display = '';
\t}

\tthis.currentAlpha = null;
\tthis.inTolerance = null;
\tthis.index = null;

\t// TODO: Reset and redraw cell states for live preview
\tif (this.preview != null)
\t{
\t\tthis.preview.destroy();
\t\tthis.preview = null;
\t}
\t
\tif (this.ghostPreview != null)
\t{
\t\tthis.ghostPreview.destroy();
\t\tthis.ghostPreview = null;
\t}

\tif (this.livePreviewActive && this.sizers != null)
\t{
\t\tfor (var i = 0; i < this.sizers.length; i++)
\t\t{
\t\t\tif (this.sizers[i] != null)
\t\t\t{
\t\t\t\tthis.sizers[i].node.style.display = '';
\t\t\t}
\t\t}
\t\t
\t\t// Shows folding icon
\t\tif (this.state.control != null && this.state.control.node != null)
\t\t{
\t\t\tthis.state.control.node.style.visibility = '';
\t\t}
\t}

\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tif (this.customHandles[i].active)
\t\t\t{
\t\t\t\tthis.customHandles[i].active = false;
\t\t\t\tthis.customHandles[i].reset();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.customHandles[i].setVisible(true);
\t\t\t}
\t\t}
\t}
\t
\t// Checks if handler has been destroyed
\tif (this.selectionBorder != null)
\t{
\t\tthis.selectionBorder.node.style.display = 'inline';
\t\tthis.selectionBounds = this.getSelectionBounds(this.state);
\t\tthis.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y,
\t\t\tthis.selectionBounds.width, this.selectionBounds.height);
\t\tthis.drawPreview();
\t}

\tthis.removeHint();
\tthis.redrawHandles();
\tthis.edgeHandlers = null;
\tthis.handlesVisible = true;
\tthis.unscaledBounds = null;
\tthis.livePreviewActive = null;
};

/**
 * Function: resizeCell
 * 
 * Uses the given vector to change the bounds of the given cell
 * in the graph using <mxGraph.resizeCell>.
 */
mxVertexHandler.prototype.resizeCell = function(cell, dx, dy, index, gridEnabled, constrained, recurse)
{
\tvar geo = this.graph.model.getGeometry(cell);
\t
\tif (geo != null)
\t{
\t\tif (index == mxEvent.LABEL_HANDLE)
\t\t{
\t\t\tvar alpha = -mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\t\tvar cos = Math.cos(alpha);
\t\t\tvar sin = Math.sin(alpha);
\t\t\tvar scale = this.graph.view.scale;
\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(
\t\t\t\tMath.round((this.labelShape.bounds.getCenterX() - this.startX) / scale),
\t\t\t\tMath.round((this.labelShape.bounds.getCenterY() - this.startY) / scale)),
\t\t\t\tcos, sin);

\t\t\tgeo = geo.clone();
\t\t\t
\t\t\tif (geo.offset == null)
\t\t\t{
\t\t\t\tgeo.offset = pt;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tgeo.offset.x += pt.x;
\t\t\t\tgeo.offset.y += pt.y;
\t\t\t}
\t\t\t
\t\t\tthis.graph.model.setGeometry(cell, geo);
\t\t}
\t\telse if (this.unscaledBounds != null)
\t\t{
\t\t\tvar scale = this.graph.view.scale;

\t\t\tif (this.childOffsetX != 0 || this.childOffsetY != 0)
\t\t\t{
\t\t\t\tthis.moveChildren(cell, Math.round(this.childOffsetX / scale), Math.round(this.childOffsetY / scale));
\t\t\t}

\t\t\tthis.graph.resizeCell(cell, this.unscaledBounds, recurse);
\t\t}
\t}
};

/**
 * Function: moveChildren
 * 
 * Moves the children of the given cell by the given vector.
 */
mxVertexHandler.prototype.moveChildren = function(cell, dx, dy)
{
\tvar model = this.graph.getModel();
\tvar childCount = model.getChildCount(cell);
\t
\tfor (var i = 0; i < childCount; i++)
\t{
\t\tvar child = model.getChildAt(cell, i);
\t\tvar geo = this.graph.getCellGeometry(child);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tgeo = geo.clone();
\t\t\tgeo.translate(dx, dy);
\t\t\tmodel.setGeometry(child, geo);
\t\t}
\t}
};
/**
 * Function: union
 * 
 * Returns the union of the given bounds and location for the specified
 * handle index.
 * 
 * To override this to limit the size of vertex via a minWidth/-Height style,
 * the following code can be used.
 * 
 * (code)
 * var vertexHandlerUnion = mxVertexHandler.prototype.union;
 * mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr, constrained)
 * {
 *   var result = vertexHandlerUnion.apply(this, arguments);
 *   
 *   result.width = Math.max(result.width, mxUtils.getNumber(this.state.style, 'minWidth', 0));
 *   result.height = Math.max(result.height, mxUtils.getNumber(this.state.style, 'minHeight', 0));
 *   
 *   return result;
 * };
 * (end)
 * 
 * The minWidth/-Height style can then be used as follows:
 * 
 * (code)
 * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'minWidth=100;minHeight=100;');
 * (end)
 * 
 * To override this to update the height for a wrapped text if the width of a vertex is
 * changed, the following can be used.
 * 
 * (code)
 * var mxVertexHandlerUnion = mxVertexHandler.prototype.union;
 * mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr, constrained)
 * {
 *   var result = mxVertexHandlerUnion.apply(this, arguments);
 *   var s = this.state;
 *   
 *   if (this.graph.isHtmlLabel(s.cell) && (index == 3 || index == 4) &&
 *       s.text != null && s.style[mxConstants.STYLE_WHITE_SPACE] == 'wrap')
 *   {
 *     var label = this.graph.getLabel(s.cell);
 *     var fontSize = mxUtils.getNumber(s.style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE);
 *     var ww = result.width / s.view.scale - s.text.spacingRight - s.text.spacingLeft
 *     
 *     result.height = mxUtils.getSizeForString(label, fontSize, s.style[mxConstants.STYLE_FONTFAMILY], ww).height;
 *   }
 *   
 *   return result;
 * };
 * (end)
 */
mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr, constrained, centered)
{
\tgridEnabled = (gridEnabled != null) ? gridEnabled && this.graph.gridEnabled : this.graph.gridEnabled;
\t
\tif (this.singleSizer)
\t{
\t\tvar x = bounds.x + bounds.width + dx;
\t\tvar y = bounds.y + bounds.height + dy;
\t\t
\t\tif (gridEnabled)
\t\t{
\t\t\tx = this.graph.snap(x / scale) * scale;
\t\t\ty = this.graph.snap(y / scale) * scale;
\t\t}
\t\t
\t\tvar rect = new mxRectangle(bounds.x, bounds.y, 0, 0);
\t\trect.add(new mxRectangle(x, y, 0, 0));
\t\t
\t\treturn rect;
\t}
\telse
\t{
\t\tvar w0 = bounds.width;
\t\tvar h0 = bounds.height;
\t\tvar left = bounds.x - tr.x * scale;
\t\tvar right = left + w0;
\t\tvar top = bounds.y - tr.y * scale;
\t\tvar bottom = top + h0;
\t\t
\t\tvar cx = left + w0 / 2;
\t\tvar cy = top + h0 / 2;
\t\t
\t\tif (index > 4 /* Bottom Row */)
\t\t{
\t\t\tbottom = bottom + dy;
\t\t\t
\t\t\tif (gridEnabled)
\t\t\t{
\t\t\t\tbottom = this.graph.snap(bottom / scale) * scale;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tbottom = Math.round(bottom / scale) * scale;
\t\t\t}
\t\t}
\t\telse if (index < 3 /* Top Row */)
\t\t{
\t\t\ttop = top + dy;
\t\t\t
\t\t\tif (gridEnabled)
\t\t\t{
\t\t\t\ttop = this.graph.snap(top / scale) * scale;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\ttop = Math.round(top / scale) * scale;
\t\t\t}
\t\t}
\t\t
\t\tif (index == 0 || index == 3 || index == 5 /* Left */)
\t\t{
\t\t\tleft += dx;
\t\t\t
\t\t\tif (gridEnabled)
\t\t\t{
\t\t\t\tleft = this.graph.snap(left / scale) * scale;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tleft = Math.round(left / scale) * scale;
\t\t\t}
\t\t}
\t\telse if (index == 2 || index == 4 || index == 7 /* Right */)
\t\t{
\t\t\tright += dx;
\t\t\t
\t\t\tif (gridEnabled)
\t\t\t{
\t\t\t\tright = this.graph.snap(right / scale) * scale;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tright = Math.round(right / scale) * scale;
\t\t\t}
\t\t}
\t\t
\t\tvar width = right - left;
\t\tvar height = bottom - top;

\t\tif (constrained)
\t\t{
\t\t\tvar geo = this.graph.getCellGeometry(this.state.cell);

\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tvar aspect = geo.width / geo.height;
\t\t\t\t
\t\t\t\tif (index== 1 || index== 2 || index == 7 || index == 6)
\t\t\t\t{
\t\t\t\t\twidth = height * aspect;
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\theight = width / aspect;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (index == 0)
\t\t\t\t{
\t\t\t\t\tleft = right - width;
\t\t\t\t\ttop = bottom - height;
\t\t\t\t}
\t\t\t}
\t\t}

\t\tif (centered)
\t\t{
\t\t\twidth += (width - w0);
\t\t\theight += (height - h0);
\t\t\t
\t\t\tvar cdx = cx - (left + width / 2);
\t\t\tvar cdy = cy - (top + height / 2);

\t\t\tleft += cdx;
\t\t\ttop += cdy;
\t\t\tright += cdx;
\t\t\tbottom += cdy;
\t\t}

\t\t// Flips over left side
\t\tif (width < 0)
\t\t{
\t\t\tleft += width;
\t\t\twidth = Math.abs(width);
\t\t}
\t\t
\t\t// Flips over top side
\t\tif (height < 0)
\t\t{
\t\t\ttop += height;
\t\t\theight = Math.abs(height);
\t\t}

\t\tvar result = new mxRectangle(left + tr.x * scale, top + tr.y * scale, width, height);
\t\t
\t\tif (this.minBounds != null)
\t\t{
\t\t\tresult.width = Math.max(result.width, this.minBounds.x * scale + this.minBounds.width * scale +
\t\t\t\tMath.max(0, this.x0 * scale - result.x));
\t\t\tresult.height = Math.max(result.height, this.minBounds.y * scale + this.minBounds.height * scale +
\t\t\t\tMath.max(0, this.y0 * scale - result.y));
\t\t}
\t\t
\t\treturn result;
\t}
};

/**
 * Function: redraw
 * 
 * Redraws the handles and the preview.
 */
mxVertexHandler.prototype.redraw = function(ignoreHandles)
{
\tthis.selectionBounds = this.getSelectionBounds(this.state);
\tthis.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y,
\t\tthis.selectionBounds.width, this.selectionBounds.height);
\tthis.drawPreview();

\tif (!ignoreHandles)
\t{
\t\tthis.redrawHandles();
\t}
};

/**
 * Returns the padding to be used for drawing handles for the current <bounds>.
 */
mxVertexHandler.prototype.getHandlePadding = function()
{
\t// KNOWN: Tolerance depends on event type (eg. 0 for mouse events)
\tvar result = new mxPoint(0, 0);
\tvar tol = this.tolerance;

\tif (this.sizers != null && this.sizers.length > 0 && this.sizers[0] != null &&
\t\t(this.bounds.width < 2 * this.sizers[0].bounds.width + 2 * tol ||
\t\tthis.bounds.height < 2 * this.sizers[0].bounds.height + 2 * tol))
\t{
\t\ttol /= 2;
\t\t
\t\tresult.x = this.sizers[0].bounds.width + tol;
\t\tresult.y = this.sizers[0].bounds.height + tol;
\t}
\t
\treturn result;
};

/**
 * Function: getSizerBounds
 * 
 * Returns the bounds used to paint the resize handles.
 */
mxVertexHandler.prototype.getSizerBounds = function()
{
\treturn this.bounds;
};

/**
 * Function: redrawHandles
 * 
 * Redraws the handles. To hide certain handles the following code can be used.
 * 
 * (code)
 * mxVertexHandler.prototype.redrawHandles = function()
 * {
 *   mxVertexHandlerRedrawHandles.apply(this, arguments);
 *   
 *   if (this.sizers != null && this.sizers.length > 7)
 *   {
 *     this.sizers[1].node.style.display = 'none';
 *     this.sizers[6].node.style.display = 'none';
 *   }
 * };
 * (end)
 */
mxVertexHandler.prototype.redrawHandles = function()
{
\tvar s = this.getSizerBounds();
\tvar tol = this.tolerance;
\tthis.horizontalOffset = 0;
\tthis.verticalOffset = 0;
\t
\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tvar temp = this.customHandles[i].shape.node.style.display;
\t\t\tthis.customHandles[i].redraw();
\t\t\tthis.customHandles[i].shape.node.style.display = temp;

\t\t\t// Hides custom handles during text editing
\t\t\tthis.customHandles[i].shape.node.style.visibility =
\t\t\t\t(this.handlesVisible && this.isCustomHandleVisible(
\t\t\t\t\tthis.customHandles[i])) ? '' : 'hidden';
\t\t}
\t}

\tif (this.sizers != null && this.sizers.length > 0 && this.sizers[0] != null)
\t{
\t\tif (this.index == null && this.manageSizers && this.sizers.length >= 8)
\t\t{
\t\t\t// KNOWN: Tolerance depends on event type (eg. 0 for mouse events)
\t\t\tvar padding = this.getHandlePadding();
\t\t\tthis.horizontalOffset = padding.x;
\t\t\tthis.verticalOffset = padding.y;
\t\t\t
\t\t\tif (this.horizontalOffset != 0 || this.verticalOffset != 0)
\t\t\t{
\t\t\t\ts = new mxRectangle(s.x, s.y, s.width, s.height);

\t\t\t\ts.x -= this.horizontalOffset / 2;
\t\t\t\ts.width += this.horizontalOffset;
\t\t\t\ts.y -= this.verticalOffset / 2;
\t\t\t\ts.height += this.verticalOffset;
\t\t\t}
\t\t\t
\t\t\tif (this.sizers.length >= 8)
\t\t\t{
\t\t\t\tif ((s.width < 2 * this.sizers[0].bounds.width + 2 * tol) ||
\t\t\t\t\t(s.height < 2 * this.sizers[0].bounds.height + 2 * tol))
\t\t\t\t{
\t\t\t\t\tthis.sizers[0].node.style.display = 'none';
\t\t\t\t\tthis.sizers[2].node.style.display = 'none';
\t\t\t\t\tthis.sizers[5].node.style.display = 'none';
\t\t\t\t\tthis.sizers[7].node.style.display = 'none';
\t\t\t\t}
\t\t\t\telse if (this.handlesVisible)
\t\t\t\t{
\t\t\t\t\tthis.sizers[0].node.style.display = '';
\t\t\t\t\tthis.sizers[2].node.style.display = '';
\t\t\t\t\tthis.sizers[5].node.style.display = '';
\t\t\t\t\tthis.sizers[7].node.style.display = '';
\t\t\t\t}
\t\t\t}
\t\t}

\t\tvar r = s.x + s.width;
\t\tvar b = s.y + s.height;
\t\t
\t\tif (this.singleSizer)
\t\t{
\t\t\tthis.moveSizerTo(this.sizers[0], r, b);
\t\t}
\t\telse
\t\t{
\t\t\tvar cx = s.x + s.width / 2;
\t\t\tvar cy = s.y + s.height / 2;
\t\t\t
\t\t\tif (this.sizers.length >= 8)
\t\t\t{
\t\t\t\tvar crs = ['nw-resize', 'n-resize', 'ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize'];
\t\t\t\t
\t\t\t\tvar alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\t\t\tvar cos = Math.cos(alpha);
\t\t\t\tvar sin = Math.sin(alpha);
\t\t\t\t
\t\t\t\tvar da = Math.round(alpha * 4 / Math.PI);
\t\t\t\t
\t\t\t\tvar ct = new mxPoint(s.getCenterX(), s.getCenterY());
\t\t\t\tvar pt = mxUtils.getRotatedPoint(new mxPoint(s.x, s.y), cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[0], pt.x, pt.y);
\t\t\t\tthis.sizers[0].setCursor(crs[mxUtils.mod(0 + da, crs.length)]);
\t\t\t\t
\t\t\t\tpt.x = cx;
\t\t\t\tpt.y = s.y;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[1], pt.x, pt.y);
\t\t\t\tthis.sizers[1].setCursor(crs[mxUtils.mod(1 + da, crs.length)]);
\t\t\t\t
\t\t\t\tpt.x = r;
\t\t\t\tpt.y = s.y;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[2], pt.x, pt.y);
\t\t\t\tthis.sizers[2].setCursor(crs[mxUtils.mod(2 + da, crs.length)]);
\t\t\t\t
\t\t\t\tpt.x = s.x;
\t\t\t\tpt.y = cy;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[3], pt.x, pt.y);
\t\t\t\tthis.sizers[3].setCursor(crs[mxUtils.mod(7 + da, crs.length)]);

\t\t\t\tpt.x = r;
\t\t\t\tpt.y = cy;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[4], pt.x, pt.y);
\t\t\t\tthis.sizers[4].setCursor(crs[mxUtils.mod(3 + da, crs.length)]);

\t\t\t\tpt.x = s.x;
\t\t\t\tpt.y = b;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[5], pt.x, pt.y);
\t\t\t\tthis.sizers[5].setCursor(crs[mxUtils.mod(6 + da, crs.length)]);

\t\t\t\tpt.x = cx;
\t\t\t\tpt.y = b;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[6], pt.x, pt.y);
\t\t\t\tthis.sizers[6].setCursor(crs[mxUtils.mod(5 + da, crs.length)]);

\t\t\t\tpt.x = r;
\t\t\t\tpt.y = b;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\t
\t\t\t\tthis.moveSizerTo(this.sizers[7], pt.x, pt.y);
\t\t\t\tthis.sizers[7].setCursor(crs[mxUtils.mod(4 + da, crs.length)]);
\t\t\t\t
\t\t\t\tpt.x = cx + this.state.absoluteOffset.x;
\t\t\t\tpt.y = cy + this.state.absoluteOffset.y;
\t\t\t\tpt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
\t\t\t\tthis.moveSizerTo(this.sizers[8], pt.x, pt.y);
\t\t\t}
\t\t\telse if (this.state.width >= 2 && this.state.height >= 2)
\t\t\t{
\t\t\t\tthis.moveSizerTo(this.sizers[0], cx + this.state.absoluteOffset.x, cy + this.state.absoluteOffset.y);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.moveSizerTo(this.sizers[0], this.state.x, this.state.y);
\t\t\t}
\t\t}
\t}

\tif (this.rotationShape != null)
\t{
\t\tvar alpha = mxUtils.toRadians((this.currentAlpha != null) ? this.currentAlpha : this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\tvar cos = Math.cos(alpha);
\t\tvar sin = Math.sin(alpha);
\t\t
\t\tvar ct = new mxPoint(this.state.getCenterX(), this.state.getCenterY());
\t\tvar pt = mxUtils.getRotatedPoint(this.getRotationHandlePosition(), cos, sin, ct);

\t\tif (this.rotationShape.node != null)
\t\t{
\t\t\tthis.moveSizerTo(this.rotationShape, pt.x, pt.y);

\t\t\t// Hides rotation handle during text editing
\t\t\tthis.rotationShape.node.style.visibility = (this.state.view.graph.isEditing() ||
\t\t\t\t!this.handlesVisible) ? 'hidden' : '';
\t\t}
\t}
\t
\tif (this.selectionBorder != null)
\t{
\t\tthis.selectionBorder.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t}
\t
\tif (this.edgeHandlers != null)
\t{\t\t
\t\tfor (var i = 0; i < this.edgeHandlers.length; i++)
\t\t{
\t\t\tthis.edgeHandlers[i].redraw();
\t\t}
\t}
};

/**
 * Function: isCustomHandleVisible
 * 
 * Returns true if the given custom handle is visible.
 */
mxVertexHandler.prototype.isCustomHandleVisible = function(handle)
{
\treturn !this.graph.isEditing() && this.state.view.graph.getSelectionCount() == 1;
};

/**
 * Function: getRotationHandlePosition
 * 
 * Returns an <mxPoint> that defines the rotation handle position.
 */
mxVertexHandler.prototype.getRotationHandlePosition = function()
{
\treturn new mxPoint(this.bounds.x + this.bounds.width / 2, this.bounds.y + this.rotationHandleVSpacing)
};

/**
 * Function: isParentHighlightVisible
 * 
 * Returns true if the parent highlight should be visible. This implementation
 * always returns true.
 */
mxVertexHandler.prototype.isParentHighlightVisible = function()
{
\treturn !this.graph.isCellSelected(this.graph.model.getParent(this.state.cell));
};

/**
 * Function: updateParentHighlight
 * 
 * Updates the highlight of the parent if <parentHighlightEnabled> is true.
 */
mxVertexHandler.prototype.updateParentHighlight = function()
{
\tif (!this.isDestroyed())
\t{
\t\tvar visible = this.isParentHighlightVisible();
\t\tvar parent = this.graph.model.getParent(this.state.cell);
\t\tvar pstate = this.graph.view.getState(parent);

\t\tif (this.parentHighlight != null)
\t\t{
\t\t\tif (this.graph.model.isVertex(parent) && visible)
\t\t\t{
\t\t\t\tvar b = this.parentHighlight.bounds;
\t\t\t\t
\t\t\t\tif (pstate != null && (b.x != pstate.x || b.y != pstate.y ||
\t\t\t\t\tb.width != pstate.width || b.height != pstate.height))
\t\t\t\t{
\t\t\t\t\tthis.parentHighlight.bounds = mxRectangle.fromRectangle(pstate);
\t\t\t\t\tthis.parentHighlight.redraw();
\t\t\t\t}
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tif (pstate != null && pstate.parentHighlight == this.parentHighlight)
\t\t\t\t{
\t\t\t\t\tpstate.parentHighlight = null;
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.parentHighlight.destroy();
\t\t\t\tthis.parentHighlight = null;
\t\t\t}
\t\t}
\t\telse if (this.parentHighlightEnabled && visible)
\t\t{
\t\t\tif (this.graph.model.isVertex(parent) && pstate != null &&
\t\t\t\tpstate.parentHighlight == null)
\t\t\t{
\t\t\t\tthis.parentHighlight = this.createParentHighlightShape(pstate);
\t\t\t\t// VML dialect required here for event transparency in IE
\t\t\t\tthis.parentHighlight.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\t\t\t\tthis.parentHighlight.pointerEvents = false;
\t\t\t\tthis.parentHighlight.rotation = Number(pstate.style[mxConstants.STYLE_ROTATION] || '0');
\t\t\t\tthis.parentHighlight.init(this.graph.getView().getOverlayPane());
\t\t\t\tthis.parentHighlight.redraw();
\t\t\t\t
\t\t\t\t// Shows highlight once per parent
\t\t\t\tpstate.parentHighlight = this.parentHighlight;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: drawPreview
 * 
 * Redraws the preview.
 */
mxVertexHandler.prototype.drawPreview = function()
{
\tif (this.preview != null)
\t{
\t\tthis.preview.bounds = this.bounds;
\t\t
\t\tif (this.preview.node.parentNode == this.graph.container)
\t\t{
\t\t\tthis.preview.bounds.width = Math.max(0, this.preview.bounds.width - 1);
\t\t\tthis.preview.bounds.height = Math.max(0, this.preview.bounds.height - 1);
\t\t}
\t
\t\tthis.preview.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\tthis.preview.redraw();
\t}
\t
\tthis.selectionBorder.bounds = this.getSelectionBorderBounds();
\tthis.selectionBorder.redraw();
\tthis.updateParentHighlight();
};

/**
 * Function: getSelectionBorderBounds
 * 
 * Returns the bounds for the selection border.
 */
mxVertexHandler.prototype.getSelectionBorderBounds = function()
{
\treturn this.bounds;
};

/**
 * Function: isDestroyed
 * 
 * Returns true if this handler was destroyed or not initialized.
 */
mxVertexHandler.prototype.isDestroyed = function()
{
\treturn this.selectionBorder == null;
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxVertexHandler.prototype.destroy = function()
{
\tif (this.escapeHandler != null)
\t{
\t\tthis.state.view.graph.removeListener(this.escapeHandler);
\t\tthis.escapeHandler = null;
\t}
\t
\tif (this.preview != null)
\t{
\t\tthis.preview.destroy();
\t\tthis.preview = null;
\t}
\t
\tif (this.parentHighlight != null)
\t{
\t\tvar parent = this.graph.model.getParent(this.state.cell);
\t\tvar pstate = this.graph.view.getState(parent);

\t\tif (pstate != null && pstate.parentHighlight == this.parentHighlight)
\t\t{
\t\t\tpstate.parentHighlight = null;
\t\t}
\t\t
\t\tthis.parentHighlight.destroy();
\t\tthis.parentHighlight = null;
\t}
\t
\tif (this.ghostPreview != null)
\t{
\t\tthis.ghostPreview.destroy();
\t\tthis.ghostPreview = null;
\t}

\tif (this.selectionBorder != null)
\t{
\t\tthis.selectionBorder.destroy();
\t\tthis.selectionBorder = null;
\t}
\t
\tthis.labelShape = null;
\tthis.removeHint();

\tif (this.sizers != null)
\t{
\t\tfor (var i = 0; i < this.sizers.length; i++)
\t\t{
\t\t\tthis.sizers[i].destroy();
\t\t}
\t\t
\t\tthis.sizers = null;
\t}

\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tthis.customHandles[i].destroy();
\t\t}
\t\t
\t\tthis.customHandles = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxEdgeHandler
 *
 * Graph event handler that reconnects edges and modifies control points and
 * the edge label location. Uses <mxTerminalMarker> for finding and
 * highlighting new source and target vertices. This handler is automatically
 * created in <mxGraph.createHandler> for each selected edge.
 * 
 * To enable adding/removing control points, the following code can be used:
 * 
 * (code)
 * mxEdgeHandler.prototype.addEnabled = true;
 * mxEdgeHandler.prototype.removeEnabled = true;
 * (end)
 * 
 * Note: This experimental feature is not recommended for production use.
 * 
 * Constructor: mxEdgeHandler
 *
 * Constructs an edge handler for the specified <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> of the cell to be handled.
 */
function mxEdgeHandler(state)
{
\tif (state != null && state.shape != null)
\t{
\t\tthis.state = state;
\t\tthis.init();
\t\t
\t\t// Handles escape keystrokes
\t\tthis.escapeHandler = mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tvar dirty = this.index != null;
\t\t\tthis.reset();
\t\t\t
\t\t\tif (dirty)
\t\t\t{
\t\t\t\tthis.graph.cellRenderer.redraw(this.state, false, state.view.isRendering());
\t\t\t}
\t\t});
\t\t
\t\tthis.state.view.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
\t}
};

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxEdgeHandler.prototype.graph = null;

/**
 * Variable: state
 * 
 * Reference to the <mxCellState> being modified.
 */
mxEdgeHandler.prototype.state = null;

/**
 * Variable: marker
 * 
 * Holds the <mxTerminalMarker> which is used for highlighting terminals.
 */
mxEdgeHandler.prototype.marker = null;

/**
 * Variable: constraintHandler
 * 
 * Holds the <mxConstraintHandler> used for drawing and highlighting
 * constraints.
 */
mxEdgeHandler.prototype.constraintHandler = null;

/**
 * Variable: error
 * 
 * Holds the current validation error while a connection is being changed.
 */
mxEdgeHandler.prototype.error = null;

/**
 * Variable: shape
 * 
 * Holds the <mxShape> that represents the preview edge.
 */
mxEdgeHandler.prototype.shape = null;

/**
 * Variable: bends
 * 
 * Holds the <mxShapes> that represent the points.
 */
mxEdgeHandler.prototype.bends = null;

/**
 * Variable: labelShape
 * 
 * Holds the <mxShape> that represents the label position.
 */
mxEdgeHandler.prototype.labelShape = null;

/**
 * Variable: cloneEnabled
 * 
 * Specifies if cloning by control-drag is enabled. Default is true.
 */
mxEdgeHandler.prototype.cloneEnabled = true;

/**
 * Variable: addEnabled
 * 
 * Specifies if adding bends by shift-click is enabled. Default is false.
 * Note: This experimental feature is not recommended for production use.
 */
mxEdgeHandler.prototype.addEnabled = false;

/**
 * Variable: removeEnabled
 * 
 * Specifies if removing bends by shift-click is enabled. Default is false.
 * Note: This experimental feature is not recommended for production use.
 */
mxEdgeHandler.prototype.removeEnabled = false;

/**
 * Variable: dblClickRemoveEnabled
 * 
 * Specifies if removing bends by double click is enabled. Default is false.
 */
mxEdgeHandler.prototype.dblClickRemoveEnabled = false;

/**
 * Variable: mergeRemoveEnabled
 * 
 * Specifies if removing bends by dropping them on other bends is enabled.
 * Default is false.
 */
mxEdgeHandler.prototype.mergeRemoveEnabled = false;

/**
 * Variable: straightRemoveEnabled
 * 
 * Specifies if removing bends by creating straight segments should be enabled.
 * If enabled, this can be overridden by holding down the alt key while moving.
 * Default is false.
 */
mxEdgeHandler.prototype.straightRemoveEnabled = false;

/**
 * Variable: virtualBendsEnabled
 * 
 * Specifies if virtual bends should be added in the center of each
 * segments. These bends can then be used to add new waypoints.
 * Default is false.
 */
mxEdgeHandler.prototype.virtualBendsEnabled = false;

/**
 * Variable: virtualBendOpacity
 * 
 * Opacity to be used for virtual bends (see <virtualBendsEnabled>).
 * Default is 20.
 */
mxEdgeHandler.prototype.virtualBendOpacity = 20;

/**
 * Variable: parentHighlightEnabled
 * 
 * Specifies if the parent should be highlighted if a child cell is selected.
 * Default is false.
 */
mxEdgeHandler.prototype.parentHighlightEnabled = false;

/**
 * Variable: preferHtml
 * 
 * Specifies if bends should be added to the graph container. This is updated
 * in <init> based on whether the edge or one of its terminals has an HTML
 * label in the container.
 */
mxEdgeHandler.prototype.preferHtml = false;

/**
 * Variable: allowHandleBoundsCheck
 * 
 * Specifies if the bounds of handles should be used for hit-detection in IE
 * Default is true.
 */
mxEdgeHandler.prototype.allowHandleBoundsCheck = true;

/**
 * Variable: snapToTerminals
 * 
 * Specifies if waypoints should snap to the routing centers of terminals.
 * Default is false.
 */
mxEdgeHandler.prototype.snapToTerminals = false;

/**
 * Variable: handleImage
 * 
 * Optional <mxImage> to be used as handles. Default is null.
 */
mxEdgeHandler.prototype.handleImage = null;

/**
 * Variable: tolerance
 * 
 * Optional tolerance for hit-detection in <getHandleForEvent>. Default is 0.
 */
mxEdgeHandler.prototype.tolerance = 0;

/**
 * Variable: outlineConnect
 * 
 * Specifies if connections to the outline of a highlighted target should be
 * enabled. This will allow to place the connection point along the outline of
 * the highlighted target. Default is false.
 */
mxEdgeHandler.prototype.outlineConnect = false;

/**
 * Variable: manageLabelHandle
 * 
 * Specifies if the label handle should be moved if it intersects with another
 * handle. Uses <checkLabelHandle> for checking and moving. Default is false.
 */
mxEdgeHandler.prototype.manageLabelHandle = false;

/**
 * Function: init
 * 
 * Initializes the shapes required for this edge handler.
 */
mxEdgeHandler.prototype.init = function()
{
\tthis.graph = this.state.view.graph;
\tthis.marker = this.createMarker();
\tthis.constraintHandler = new mxConstraintHandler(this.graph);
\t
\t// Clones the original points from the cell
\t// and makes sure at least one point exists
\tthis.points = [];
\t
\t// Uses the absolute points of the state
\t// for the initial configuration and preview
\tthis.abspoints = this.getSelectionPoints(this.state);
\tthis.shape = this.createSelectionShape(this.abspoints);
\tthis.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\tmxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
\tthis.shape.init(this.graph.getView().getOverlayPane());
\tthis.shape.pointerEvents = false;
\tthis.shape.setCursor(mxConstants.CURSOR_MOVABLE_EDGE);
\tmxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);

\t// Updates preferHtml
\tthis.preferHtml = this.state.text != null &&
\t\tthis.state.text.node.parentNode == this.graph.container;
\t
\tif (!this.preferHtml)
\t{
\t\t// Checks source terminal
\t\tvar sourceState = this.state.getVisibleTerminalState(true);
\t\t
\t\tif (sourceState != null)
\t\t{
\t\t\tthis.preferHtml = sourceState.text != null &&
\t\t\t\tsourceState.text.node.parentNode == this.graph.container;
\t\t}
\t\t
\t\tif (!this.preferHtml)
\t\t{
\t\t\t// Checks target terminal
\t\t\tvar targetState = this.state.getVisibleTerminalState(false);
\t\t\t
\t\t\tif (targetState != null)
\t\t\t{
\t\t\t\tthis.preferHtml = targetState.text != null &&
\t\t\t\ttargetState.text.node.parentNode == this.graph.container;
\t\t\t}
\t\t}
\t}

\t// Creates bends for the non-routed absolute points
\t// or bends that don't correspond to points
\tif (this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells ||
\t\tmxGraphHandler.prototype.maxCells <= 0)
\t{
\t\tthis.bends = this.createBends();

\t\tif (this.isVirtualBendsEnabled())
\t\t{
\t\t\tthis.virtualBends = this.createVirtualBends();
\t\t}
\t}

\t// Adds a rectangular handle for the label position
\tthis.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
\tthis.labelShape = this.createLabelHandleShape();
\tthis.initBend(this.labelShape);
\tthis.labelShape.setCursor(mxConstants.CURSOR_LABEL_HANDLE);
\t
\tthis.customHandles = this.createCustomHandles();
\t
\tthis.updateParentHighlight();
\tthis.redraw();
};


/**
 * Function: isParentHighlightVisible
 * 
 * Returns true if the parent highlight should be visible. This implementation
 * always returns true.
 */
mxEdgeHandler.prototype.isParentHighlightVisible = mxVertexHandler.prototype.isParentHighlightVisible;

/**
 * Function: updateParentHighlight
 * 
 * Updates the highlight of the parent if <parentHighlightEnabled> is true.
 */
mxEdgeHandler.prototype.updateParentHighlight = mxVertexHandler.prototype.updateParentHighlight;

/**
 * Function: createCustomHandles
 * 
 * Returns an array of custom handles. This implementation returns null.
 */
mxEdgeHandler.prototype.createCustomHandles = function()
{
\treturn null;
};

/**
 * Function: isVirtualBendsEnabled
 * 
 * Returns true if virtual bends should be added. This returns true if
 * <virtualBendsEnabled> is true and the current style allows and
 * renders custom waypoints.
 */
mxEdgeHandler.prototype.isVirtualBendsEnabled = function(evt)
{
\treturn this.virtualBendsEnabled && (this.state.style[mxConstants.STYLE_EDGE] == null ||
\t\t\tthis.state.style[mxConstants.STYLE_EDGE] == mxConstants.NONE ||
\t\t\tthis.state.style[mxConstants.STYLE_NOEDGESTYLE] == 1)  &&
\t\t\tmxUtils.getValue(this.state.style, mxConstants.STYLE_SHAPE, null) != 'arrow';
};

/**
 * Function: isCellEnabled
 * 
 * Returns true if the given cell allows new connections to be created. This implementation
 * always returns true.
 */
mxEdgeHandler.prototype.isCellEnabled = function(cell)
{
\treturn true;
};

/**
 * Function: isAddPointEvent
 * 
 * Returns true if the given event is a trigger to add a new point. This
 * implementation returns true if shift is pressed.
 */
mxEdgeHandler.prototype.isAddPointEvent = function(evt)
{
\treturn mxEvent.isShiftDown(evt);
};

/**
 * Function: isRemovePointEvent
 * 
 * Returns true if the given event is a trigger to remove a point. This
 * implementation returns true if shift is pressed.
 */
mxEdgeHandler.prototype.isRemovePointEvent = function(evt)
{
\treturn mxEvent.isShiftDown(evt);
};

/**
 * Function: getSelectionPoints
 * 
 * Returns the list of points that defines the selection stroke.
 */
mxEdgeHandler.prototype.getSelectionPoints = function(state)
{
\treturn state.absolutePoints;
};

/**
 * Function: createParentHighlightShape
 * 
 * Creates the shape used to draw the selection border.
 */
mxEdgeHandler.prototype.createParentHighlightShape = function(bounds)
{
\tvar shape = new mxRectangleShape(mxRectangle.fromRectangle(bounds),
\t\tnull, this.getSelectionColor());
\tshape.strokewidth = this.getSelectionStrokeWidth();
\tshape.isDashed = this.isSelectionDashed();
\t
\treturn shape;
};

/**
 * Function: createSelectionShape
 * 
 * Creates the shape used to draw the selection border.
 */
mxEdgeHandler.prototype.createSelectionShape = function(points)
{
\tvar shape = new this.state.shape.constructor();
\tshape.outline = true;
\tshape.apply(this.state);
\t
\tshape.isDashed = this.isSelectionDashed();
\tshape.stroke = this.getSelectionColor();
\tshape.isShadow = false;
\t
\treturn shape;
};

/**
 * Function: getSelectionColor
 * 
 * Returns <mxConstants.EDGE_SELECTION_COLOR>.
 */
mxEdgeHandler.prototype.getSelectionColor = function()
{
\treturn mxConstants.EDGE_SELECTION_COLOR;
};

/**
 * Function: getSelectionStrokeWidth
 * 
 * Returns <mxConstants.EDGE_SELECTION_STROKEWIDTH>.
 */
mxEdgeHandler.prototype.getSelectionStrokeWidth = function()
{
\treturn mxConstants.EDGE_SELECTION_STROKEWIDTH;
};

/**
 * Function: isSelectionDashed
 * 
 * Returns <mxConstants.EDGE_SELECTION_DASHED>.
 */
mxEdgeHandler.prototype.isSelectionDashed = function()
{
\treturn mxConstants.EDGE_SELECTION_DASHED;
};

/**
 * Function: isConnectableCell
 * 
 * Returns true if the given cell is connectable. This is a hook to
 * disable floating connections. This implementation returns true.
 */
mxEdgeHandler.prototype.isConnectableCell = function(cell)
{
\treturn true;
};

/**
 * Function: getCellAt
 * 
 * Creates and returns the <mxCellMarker> used in <marker>.
 */
mxEdgeHandler.prototype.getCellAt = function(x, y)
{
\treturn (!this.outlineConnect) ? this.graph.getCellAt(x, y) : null;
};

/**
 * Function: createMarker
 * 
 * Creates and returns the <mxCellMarker> used in <marker>.
 */
mxEdgeHandler.prototype.createMarker = function()
{
\tvar marker = new mxCellMarker(this.graph);
\tvar self = this; // closure

\t// Only returns edges if they are connectable and never returns
\t// the edge that is currently being modified
\tmarker.getCell = function(me)
\t{
\t\tvar cell = mxCellMarker.prototype.getCell.apply(this, arguments);

\t\t// Checks for cell at preview point (with grid)
\t\tif ((cell == self.state.cell || cell == null) && self.currentPoint != null)
\t\t{
\t\t\tcell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
\t\t}
\t\t
\t\t// Uses connectable parent vertex if one exists
\t\tif (cell != null && !this.graph.isCellConnectable(cell))
\t\t{
\t\t\tvar parent = this.graph.getModel().getParent(cell);
\t\t\t
\t\t\tif (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
\t\t\t{
\t\t\t\tcell = parent;
\t\t\t}
\t\t}
\t\t
\t\tvar model = self.graph.getModel();
\t\t
\t\tif ((this.graph.isSwimlane(cell) && self.currentPoint != null &&
\t\t\tthis.graph.hitsSwimlaneContent(cell, self.currentPoint.x, self.currentPoint.y)) ||
\t\t\t(!self.isConnectableCell(cell)) || (cell == self.state.cell ||
\t\t\t(cell != null && !self.graph.connectableEdges && model.isEdge(cell))) ||
\t\t\tmodel.isAncestor(self.state.cell, cell))
\t\t{
\t\t\tcell = null;
\t\t}
\t\t
\t\tif (!this.graph.isCellConnectable(cell))
\t\t{
\t\t\tcell = null;
\t\t}
\t\t
\t\treturn cell;
\t};

\t// Sets the highlight color according to validateConnection
\tmarker.isValidState = function(state)
\t{
\t\tvar model = self.graph.getModel();
\t\tvar other = self.graph.view.getTerminalPort(state,
\t\t\tself.graph.view.getState(model.getTerminal(self.state.cell,
\t\t\t!self.isSource)), !self.isSource);
\t\tvar otherCell = (other != null) ? other.cell : null;
\t\tvar source = (self.isSource) ? state.cell : otherCell;
\t\tvar target = (self.isSource) ? otherCell : state.cell;
\t\t
\t\t// Updates the error message of the handler
\t\tself.error = self.validateConnection(source, target);

\t\treturn self.error == null;
\t};
\t
\treturn marker;
};

/**
 * Function: validateConnection
 * 
 * Returns the error message or an empty string if the connection for the
 * given source, target pair is not valid. Otherwise it returns null. This
 * implementation uses <mxGraph.getEdgeValidationError>.
 * 
 * Parameters:
 * 
 * source - <mxCell> that represents the source terminal.
 * target - <mxCell> that represents the target terminal.
 */
mxEdgeHandler.prototype.validateConnection = function(source, target)
{
\treturn this.graph.getEdgeValidationError(this.state.cell, source, target);
};

/**
 * Function: createBends
 * 
 * Creates and returns the bends used for modifying the edge. This is
 * typically an array of <mxRectangleShapes>.
 */
 mxEdgeHandler.prototype.createBends = function()
 {
\tvar cell = this.state.cell;
\tvar bends = [];

\tfor (var i = 0; i < this.abspoints.length; i++)
\t{
\t\tif (this.isHandleVisible(i))
\t\t{
\t\t\tvar source = i == 0;
\t\t\tvar target = i == this.abspoints.length - 1;
\t\t\tvar terminal = source || target;

\t\t\tif (terminal || this.graph.isCellBendable(cell))
\t\t\t{
\t\t\t\t(mxUtils.bind(this, function(index)
\t\t\t\t{
\t\t\t\t\tvar bend = this.createHandleShape(index);
\t\t\t\t\tthis.initBend(bend, mxUtils.bind(this, mxUtils.bind(this, function()
\t\t\t\t\t{
\t\t\t\t\t\tif (this.dblClickRemoveEnabled)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.removePoint(this.state, index);
\t\t\t\t\t\t}
\t\t\t\t\t})));
\t
\t\t\t\t\tif (this.isHandleEnabled(i))
\t\t\t\t\t{
\t\t\t\t\t\tbend.setCursor((terminal) ? mxConstants.CURSOR_TERMINAL_HANDLE : mxConstants.CURSOR_BEND_HANDLE);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tbends.push(bend);
\t\t\t\t
\t\t\t\t\tif (!terminal)
\t\t\t\t\t{
\t\t\t\t\t\tthis.points.push(new mxPoint(0,0));
\t\t\t\t\t\tbend.node.style.visibility = 'hidden';
\t\t\t\t\t}
\t\t\t\t}))(i);
\t\t\t}
\t\t}
\t}

\treturn bends;
};

/**
 * Function: createVirtualBends
 * 
 * Creates and returns the bends used for modifying the edge. This is
 * typically an array of <mxRectangleShapes>.
 */
 mxEdgeHandler.prototype.createVirtualBends = function()
 {
\tvar cell = this.state.cell;
\tvar last = this.abspoints[0];
\tvar bends = [];

\tif (this.graph.isCellBendable(cell))
\t{
\t\tfor (var i = 1; i < this.abspoints.length; i++)
\t\t{
\t\t\t(mxUtils.bind(this, function(bend)
\t\t\t{
\t\t\t\tthis.initBend(bend);
\t\t\t\tbend.setCursor(mxConstants.CURSOR_VIRTUAL_BEND_HANDLE);
\t\t\t\tbends.push(bend);
\t\t\t}))(this.createHandleShape());
\t\t}
\t}

\treturn bends;
};

/**
 * Function: isHandleEnabled
 * 
 * Creates the shape used to display the given bend.
 */
mxEdgeHandler.prototype.isHandleEnabled = function(index)
{
\treturn true;
};

/**
 * Function: isHandleVisible
 * 
 * Returns true if the handle at the given index is visible.
 */
mxEdgeHandler.prototype.isHandleVisible = function(index)
{
\tvar source = this.state.getVisibleTerminalState(true);
\tvar target = this.state.getVisibleTerminalState(false);
\tvar geo = this.graph.getCellGeometry(this.state.cell);
\tvar edgeStyle = (geo != null) ? this.graph.view.getEdgeStyle(this.state, geo.points, source, target) : null;

\treturn edgeStyle != mxEdgeStyle.EntityRelation || index == 0 || index == this.abspoints.length - 1;
};

/**
 * Function: createHandleShape
 * 
 * Creates the shape used to display the given bend. Note that the index may be
 * null for special cases, such as when called from
 * <mxElbowEdgeHandler.createVirtualBend>. Only images and rectangles should be
 * returned if support for HTML labels with not foreign objects is required.
 * Index if null for virtual handles.
 */
mxEdgeHandler.prototype.createHandleShape = function(index)
{
\tif (this.handleImage != null)
\t{
\t\tvar shape = new mxImageShape(new mxRectangle(0, 0, this.handleImage.width, this.handleImage.height), this.handleImage.src);
\t\t
\t\t// Allows HTML rendering of the images
\t\tshape.preserveImageAspect = false;

\t\treturn shape;
\t}
\telse
\t{
\t\tvar s = mxConstants.HANDLE_SIZE;
\t\t
\t\tif (this.preferHtml)
\t\t{
\t\t\ts -= 1;
\t\t}
\t\t
\t\treturn new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
\t}
};

/**
 * Function: createLabelHandleShape
 * 
 * Creates the shape used to display the the label handle.
 */
mxEdgeHandler.prototype.createLabelHandleShape = function()
{
\tif (this.labelHandleImage != null)
\t{
\t\tvar shape = new mxImageShape(new mxRectangle(0, 0, this.labelHandleImage.width, this.labelHandleImage.height), this.labelHandleImage.src);
\t\t
\t\t// Allows HTML rendering of the images
\t\tshape.preserveImageAspect = false;

\t\treturn shape;
\t}
\telse
\t{
\t\tvar s = mxConstants.LABEL_HANDLE_SIZE;
\t\treturn new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.LABEL_HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
\t}
};

/**
 * Function: initBend
 * 
 * Helper method to initialize the given bend.
 * 
 * Parameters:
 * 
 * bend - <mxShape> that represents the bend to be initialized.
 */
mxEdgeHandler.prototype.initBend = function(bend, dblClick)
{
\tif (this.preferHtml)
\t{
\t\tbend.dialect = mxConstants.DIALECT_STRICTHTML;
\t\tbend.init(this.graph.container);
\t}
\telse
\t{
\t\tbend.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
\t\t\tmxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
\t\tbend.init(this.graph.getView().getOverlayPane());
\t}

\tmxEvent.redirectMouseEvents(bend.node, this.graph, this.state,
\t\t\tnull, null, null, dblClick);
\t
\t// Fixes lost event tracking for images in quirks / IE8 standards
\tif (mxClient.IS_QUIRKS || document.documentMode == 8)
\t{
\t\tmxEvent.addListener(bend.node, 'dragstart', function(evt)
\t\t{
\t\t\tmxEvent.consume(evt);
\t\t\t
\t\t\treturn false;
\t\t});
\t}
\t
\tif (mxClient.IS_TOUCH)
\t{
\t\tbend.node.setAttribute('pointer-events', 'none');
\t}
};

/**
 * Function: getHandleForEvent
 * 
 * Returns the index of the handle for the given event.
 */
mxEdgeHandler.prototype.getHandleForEvent = function(me)
{
\tvar result = null;
\t
\tif (this.state != null)
\t{
\t\t// Connection highlight may consume events before they reach sizer handle
\t\tvar tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.tolerance : 1;
\t\tvar hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
\t\t\tnew mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
\t\tvar minDistSq = null;
\t
\t\tfunction checkShape(shape)
\t\t{
\t\t\tif (shape != null && shape.node != null && shape.node.style.display != 'none' &&
\t\t\t\tshape.node.style.visibility != 'hidden' &&
\t\t\t\t(me.isSource(shape) || (hit != null && mxUtils.intersects(shape.bounds, hit))))
\t\t\t{
\t\t\t\tvar dx = me.getGraphX() - shape.bounds.getCenterX();
\t\t\t\tvar dy = me.getGraphY() - shape.bounds.getCenterY();
\t\t\t\tvar tmp = dx * dx + dy * dy;
\t\t\t\t
\t\t\t\tif (minDistSq == null || tmp <= minDistSq)
\t\t\t\t{
\t\t\t\t\tminDistSq = tmp;
\t\t\t\t
\t\t\t\t\treturn true;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\treturn false;
\t\t}
\t\t
\t\tif (this.customHandles != null && this.isCustomHandleEvent(me))
\t\t{
\t\t\t// Inverse loop order to match display order
\t\t\tfor (var i = this.customHandles.length - 1; i >= 0; i--)
\t\t\t{
\t\t\t\tif (checkShape(this.customHandles[i].shape))
\t\t\t\t{
\t\t\t\t\t// LATER: Return reference to active shape
\t\t\t\t\treturn mxEvent.CUSTOM_HANDLE - i;
\t\t\t\t}
\t\t\t}
\t\t}
\t
\t\tif (me.isSource(this.state.text) || checkShape(this.labelShape))
\t\t{
\t\t\tresult = mxEvent.LABEL_HANDLE;
\t\t}
\t\t
\t\tif (this.bends != null)
\t\t{
\t\t\tfor (var i = 0; i < this.bends.length; i++)
\t\t\t{
\t\t\t\tif (checkShape(this.bends[i]))
\t\t\t\t{
\t\t\t\t\tresult = i;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (this.virtualBends != null && this.isAddVirtualBendEvent(me))
\t\t{
\t\t\tfor (var i = 0; i < this.virtualBends.length; i++)
\t\t\t{
\t\t\t\tif (checkShape(this.virtualBends[i]))
\t\t\t\t{
\t\t\t\t\tresult = mxEvent.VIRTUAL_HANDLE - i;
\t\t\t\t}
\t\t\t}
\t\t}
\t}

\treturn result;
};

/**
 * Function: isAddVirtualBendEvent
 * 
 * Returns true if the given event allows virtual bends to be added. This
 * implementation returns true.
 */
mxEdgeHandler.prototype.isAddVirtualBendEvent = function(me)
{
\treturn true;
};

/**
 * Function: isCustomHandleEvent
 * 
 * Returns true if the given event allows custom handles to be changed. This
 * implementation returns true.
 */
mxEdgeHandler.prototype.isCustomHandleEvent = function(me)
{
\treturn true;
};

/**
 * Function: mouseDown
 * 
 * Handles the event by checking if a special element of the handler
 * was clicked, in which case the index parameter is non-null. The
 * indices may be one of <LABEL_HANDLE> or the number of the respective
 * control point. The source and target points are used for reconnecting
 * the edge.
 */
mxEdgeHandler.prototype.mouseDown = function(sender, me)
{
\tvar handle = this.getHandleForEvent(me);
\t
\tif (this.bends != null && this.bends[handle] != null)
\t{
\t\tvar b = this.bends[handle].bounds;
\t\tthis.snapPoint = new mxPoint(b.getCenterX(), b.getCenterY());
\t}
\t
\tif (this.addEnabled && handle == null && this.isAddPointEvent(me.getEvent()))
\t{
\t\tthis.addPoint(this.state, me.getEvent());
\t\tme.consume();
\t}
\telse if (handle != null && !me.isConsumed() && this.graph.isEnabled())
\t{
\t\tif (this.removeEnabled && this.isRemovePointEvent(me.getEvent()))
\t\t{
\t\t\tthis.removePoint(this.state, handle);
\t\t}
\t\telse if (handle != mxEvent.LABEL_HANDLE || this.graph.isLabelMovable(me.getCell()))
\t\t{
\t\t\tif (handle <= mxEvent.VIRTUAL_HANDLE)
\t\t\t{
\t\t\t\tmxUtils.setOpacity(this.virtualBends[mxEvent.VIRTUAL_HANDLE - handle].node, 100);
\t\t\t}
\t\t\t
\t\t\tthis.start(me.getX(), me.getY(), handle);
\t\t}
\t\t
\t\tme.consume();
\t}
};

/**
 * Function: start
 * 
 * Starts the handling of the mouse gesture.
 */
mxEdgeHandler.prototype.start = function(x, y, index)
{
\tthis.startX = x;
\tthis.startY = y;

\tthis.isSource = (this.bends == null) ? false : index == 0;
\tthis.isTarget = (this.bends == null) ? false : index == this.bends.length - 1;
\tthis.isLabel = index == mxEvent.LABEL_HANDLE;

\tif (this.isSource || this.isTarget)
\t{
\t\tvar cell = this.state.cell;
\t\tvar terminal = this.graph.model.getTerminal(cell, this.isSource);

\t\tif ((terminal == null && this.graph.isTerminalPointMovable(cell, this.isSource)) ||
\t\t\t(terminal != null && this.graph.isCellDisconnectable(cell, terminal, this.isSource)))
\t\t{
\t\t\tthis.index = index;
\t\t}
\t}
\telse
\t{
\t\tthis.index = index;
\t}
\t
\t// Hides other custom handles
\tif (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
\t{
\t\tif (this.customHandles != null)
\t\t{
\t\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t\t{
\t\t\t\tif (i != mxEvent.CUSTOM_HANDLE - this.index)
\t\t\t\t{
\t\t\t\t\tthis.customHandles[i].setVisible(false);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
};

/**
 * Function: clonePreviewState
 * 
 * Returns a clone of the current preview state for the given point and terminal.
 */
mxEdgeHandler.prototype.clonePreviewState = function(point, terminal)
{
\treturn this.state.clone();
};

/**
 * Function: getSnapToTerminalTolerance
 * 
 * Returns the tolerance for the guides. Default value is
 * gridSize * scale / 2.
 */
mxEdgeHandler.prototype.getSnapToTerminalTolerance = function()
{
\treturn this.graph.gridSize * this.graph.view.scale / 2;
};

/**
 * Function: updateHint
 * 
 * Hook for subclassers do show details while the handler is active.
 */
mxEdgeHandler.prototype.updateHint = function(me, point) { };

/**
 * Function: removeHint
 * 
 * Hooks for subclassers to hide details when the handler gets inactive.
 */
mxEdgeHandler.prototype.removeHint = function() { };

/**
 * Function: roundLength
 * 
 * Hook for rounding the unscaled width or height. This uses Math.round.
 */
mxEdgeHandler.prototype.roundLength = function(length)
{
\treturn Math.round(length);
};

/**
 * Function: isSnapToTerminalsEvent
 * 
 * Returns true if <snapToTerminals> is true and if alt is not pressed.
 */
mxEdgeHandler.prototype.isSnapToTerminalsEvent = function(me)
{
\treturn this.snapToTerminals && !mxEvent.isAltDown(me.getEvent());
};

/**
 * Function: getPointForEvent
 * 
 * Returns the point for the given event.
 */
mxEdgeHandler.prototype.getPointForEvent = function(me)
{
\tvar view = this.graph.getView();
\tvar scale = view.scale;
\tvar point = new mxPoint(this.roundLength(me.getGraphX() / scale) * scale,
\t\tthis.roundLength(me.getGraphY() / scale) * scale);
\t
\tvar tt = this.getSnapToTerminalTolerance();
\tvar overrideX = false;
\tvar overrideY = false;\t\t
\t
\tif (tt > 0 && this.isSnapToTerminalsEvent(me))
\t{
\t\tfunction snapToPoint(pt)
\t\t{
\t\t\tif (pt != null)
\t\t\t{
\t\t\t\tvar x = pt.x;

\t\t\t\tif (Math.abs(point.x - x) < tt)
\t\t\t\t{
\t\t\t\t\tpoint.x = x;
\t\t\t\t\toverrideX = true;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar y = pt.y;

\t\t\t\tif (Math.abs(point.y - y) < tt)
\t\t\t\t{
\t\t\t\t\tpoint.y = y;
\t\t\t\t\toverrideY = true;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\t// Temporary function
\t\tfunction snapToTerminal(terminal)
\t\t{
\t\t\tif (terminal != null)
\t\t\t{
\t\t\t\tsnapToPoint.call(this, new mxPoint(view.getRoutingCenterX(terminal),
\t\t\t\t\t\tview.getRoutingCenterY(terminal)));
\t\t\t}
\t\t};

\t\tsnapToTerminal.call(this, this.state.getVisibleTerminalState(true));
\t\tsnapToTerminal.call(this, this.state.getVisibleTerminalState(false));

\t\tif (this.state.absolutePoints != null)
\t\t{
\t\t\tfor (var i = 0; i < this.state.absolutePoints.length; i++)
\t\t\t{
\t\t\t\tsnapToPoint.call(this, this.state.absolutePoints[i]);
\t\t\t}
\t\t}
\t}

\tif (this.graph.isGridEnabledEvent(me.getEvent()))
\t{
\t\tvar tr = view.translate;
\t\t
\t\tif (!overrideX)
\t\t{
\t\t\tpoint.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale;
\t\t}
\t\t
\t\tif (!overrideY)
\t\t{
\t\t\tpoint.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale;
\t\t}
\t}
\t
\treturn point;
};

/**
 * Function: getPreviewTerminalState
 * 
 * Updates the given preview state taking into account the state of the constraint handler.
 */
mxEdgeHandler.prototype.getPreviewTerminalState = function(me)
{
\tthis.constraintHandler.update(me, this.isSource, true, me.isSource(this.marker.highlight.shape) ? null : this.currentPoint);
\t
\tif (this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null)
\t{
\t\t// Handles special case where grid is large and connection point is at actual point in which
\t\t// case the outline is not followed as long as we're < gridSize / 2 away from that point
\t\tif (this.marker.highlight != null && this.marker.highlight.state != null &&
\t\t\tthis.marker.highlight.state.cell == this.constraintHandler.currentFocus.cell)
\t\t{
\t\t\t// Direct repaint needed if cell already highlighted
\t\t\tif (this.marker.highlight.shape.stroke != 'transparent')
\t\t\t{
\t\t\t\tthis.marker.highlight.shape.stroke = 'transparent';
\t\t\t\tthis.marker.highlight.repaint();
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tthis.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
\t\t}
\t\t
\t\tvar model = this.graph.getModel();
\t\tvar other = this.graph.view.getTerminalPort(this.state,
\t\t\t\tthis.graph.view.getState(model.getTerminal(this.state.cell,
\t\t\t!this.isSource)), !this.isSource);
\t\tvar otherCell = (other != null) ? other.cell : null;
\t\tvar source = (this.isSource) ? this.constraintHandler.currentFocus.cell : otherCell;
\t\tvar target = (this.isSource) ? otherCell : this.constraintHandler.currentFocus.cell;
\t\t
\t\t// Updates the error message of the handler
\t\tthis.error = this.validateConnection(source, target);
\t\tvar result = null;
\t\t
\t\tif (this.error == null)
\t\t{
\t\t\tresult = this.constraintHandler.currentFocus;
\t\t}
\t\t
\t\tif (this.error != null || (result != null &&
\t\t\t!this.isCellEnabled(result.cell)))
\t\t{
\t\t\tthis.constraintHandler.reset();
\t\t}
\t\t
\t\treturn result;
\t}
\telse if (!this.graph.isIgnoreTerminalEvent(me.getEvent()))
\t{
\t\tthis.marker.process(me);
\t\tvar state = this.marker.getValidState();
\t\t
\t\tif (state != null && !this.isCellEnabled(state.cell))
\t\t{
\t\t\tthis.constraintHandler.reset();
\t\t\tthis.marker.reset();
\t\t}
\t\t
\t\treturn this.marker.getValidState();
\t}
\telse
\t{
\t\tthis.marker.reset();
\t\t
\t\treturn null;
\t}
};

/**
 * Function: getPreviewPoints
 * 
 * Updates the given preview state taking into account the state of the constraint handler.
 * 
 * Parameters:
 * 
 * pt - <mxPoint> that contains the current pointer position.
 * me - Optional <mxMouseEvent> that contains the current event.
 */
mxEdgeHandler.prototype.getPreviewPoints = function(pt, me)
{
\tvar geometry = this.graph.getCellGeometry(this.state.cell);
\tvar points = (geometry.points != null) ? geometry.points.slice() : null;
\tvar point = new mxPoint(pt.x, pt.y);
\tvar result = null;
\t
\tif (!this.isSource && !this.isTarget)
\t{
\t\tthis.convertPoint(point, false);
\t\t
\t\tif (points == null)
\t\t{
\t\t\tpoints = [point];
\t\t}
\t\telse
\t\t{
\t\t\t// Adds point from virtual bend
\t\t\tif (this.index <= mxEvent.VIRTUAL_HANDLE)
\t\t\t{
\t\t\t\tpoints.splice(mxEvent.VIRTUAL_HANDLE - this.index, 0, point);
\t\t\t}

\t\t\t// Removes point if dragged on terminal point
\t\t\tif (!this.isSource && !this.isTarget)
\t\t\t{
\t\t\t\tfor (var i = 0; i < this.bends.length; i++)
\t\t\t\t{
\t\t\t\t\tif (i != this.index)
\t\t\t\t\t{
\t\t\t\t\t\tvar bend = this.bends[i];
\t\t\t\t\t\t
\t\t\t\t\t\tif (bend != null && mxUtils.contains(bend.bounds, pt.x, pt.y))
\t\t\t\t\t\t{
\t\t\t\t\t\t\tif (this.index <= mxEvent.VIRTUAL_HANDLE)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tpoints.splice(mxEvent.VIRTUAL_HANDLE - this.index, 1);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tpoints.splice(this.index - 1, 1);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tresult = points;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// Removes point if user tries to straighten a segment
\t\t\t\tif (result == null && this.straightRemoveEnabled && (me == null || !mxEvent.isAltDown(me.getEvent())))
\t\t\t\t{
\t\t\t\t\tvar tol = this.graph.tolerance * this.graph.tolerance;
\t\t\t\t\tvar abs = this.state.absolutePoints.slice();
\t\t\t\t\tabs[this.index] = pt;
\t\t\t\t\t
\t\t\t\t\t// Handes special case where removing waypoint affects tolerance (flickering)
\t\t\t\t\tvar src = this.state.getVisibleTerminalState(true);
\t\t\t\t\t
\t\t\t\t\tif (src != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar c = this.graph.getConnectionConstraint(this.state, src, true);
\t\t\t\t\t\t
\t\t\t\t\t\t// Checks if point is not fixed
\t\t\t\t\t\tif (c == null || this.graph.getConnectionPoint(src, c) == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tabs[0] = new mxPoint(src.view.getRoutingCenterX(src), src.view.getRoutingCenterY(src));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tvar trg = this.state.getVisibleTerminalState(false);
\t\t\t\t\t
\t\t\t\t\tif (trg != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar c = this.graph.getConnectionConstraint(this.state, trg, false);
\t\t\t\t\t\t
\t\t\t\t\t\t// Checks if point is not fixed
\t\t\t\t\t\tif (c == null || this.graph.getConnectionPoint(trg, c) == null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tabs[abs.length - 1] = new mxPoint(trg.view.getRoutingCenterX(trg), trg.view.getRoutingCenterY(trg));
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\tfunction checkRemove(idx, tmp)
\t\t\t\t\t{
\t\t\t\t\t\tif (idx > 0 && idx < abs.length - 1 &&
\t\t\t\t\t\t\tmxUtils.ptSegDistSq(abs[idx - 1].x, abs[idx - 1].y,
\t\t\t\t\t\t\t\tabs[idx + 1].x, abs[idx + 1].y, tmp.x, tmp.y) < tol)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tpoints.splice(idx - 1, 1);
\t\t\t\t\t\t\tresult = points;
\t\t\t\t\t\t}
\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\t// LATER: Check if other points can be removed if a segment is made straight
\t\t\t\t\tcheckRemove(this.index, pt);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Updates existing point
\t\t\tif (result == null && this.index > mxEvent.VIRTUAL_HANDLE)
\t\t\t{
\t\t\t\tpoints[this.index - 1] = point;
\t\t\t}
\t\t}
\t}
\telse if (this.graph.resetEdgesOnConnect)
\t{
\t\tpoints = null;
\t}
\t
\treturn (result != null) ? result : points;
};

/**
 * Function: isOutlineConnectEvent
 * 
 * Returns true if <outlineConnect> is true and the source of the event is the outline shape
 * or shift is pressed.
 */
mxEdgeHandler.prototype.isOutlineConnectEvent = function(me)
{
\tvar offset = mxUtils.getOffset(this.graph.container);
\tvar evt = me.getEvent();
\t
\tvar clientX = mxEvent.getClientX(evt);
\tvar clientY = mxEvent.getClientY(evt);
\t
\tvar doc = document.documentElement;
\tvar left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
\tvar top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
\t
\tvar gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
\tvar gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;

\treturn this.outlineConnect && !mxEvent.isShiftDown(me.getEvent()) &&
\t\t(me.isSource(this.marker.highlight.shape) ||
\t\t(mxEvent.isAltDown(me.getEvent()) && me.getState() != null) ||
\t\tthis.marker.highlight.isHighlightAt(clientX, clientY) ||
\t\t((gridX != clientX || gridY != clientY) && me.getState() == null &&
\t\tthis.marker.highlight.isHighlightAt(gridX, gridY)));
};

/**
 * Function: updatePreviewState
 * 
 * Updates the given preview state taking into account the state of the constraint handler.
 */
mxEdgeHandler.prototype.updatePreviewState = function(edge, point, terminalState, me, outline)
{
\t// Computes the points for the edge style and terminals
\tvar sourceState = (this.isSource) ? terminalState : this.state.getVisibleTerminalState(true);
\tvar targetState = (this.isTarget) ? terminalState : this.state.getVisibleTerminalState(false);
\t
\tvar sourceConstraint = this.graph.getConnectionConstraint(edge, sourceState, true);
\tvar targetConstraint = this.graph.getConnectionConstraint(edge, targetState, false);

\tvar constraint = this.constraintHandler.currentConstraint;

\tif (constraint == null && outline)
\t{
\t\tif (terminalState != null)
\t\t{
\t\t\t// Handles special case where mouse is on outline away from actual end point
\t\t\t// in which case the grid is ignored and mouse point is used instead
\t\t\tif (me.isSource(this.marker.highlight.shape))
\t\t\t{
\t\t\t\tpoint = new mxPoint(me.getGraphX(), me.getGraphY());
\t\t\t}
\t\t\t
\t\t\tconstraint = this.graph.getOutlineConstraint(point, terminalState, me);
\t\t\tthis.constraintHandler.setFocus(me, terminalState, this.isSource);
\t\t\tthis.constraintHandler.currentConstraint = constraint;
\t\t\tthis.constraintHandler.currentPoint = point;
\t\t}
\t\telse
\t\t{
\t\t\tconstraint = new mxConnectionConstraint();
\t\t}
\t}
\t
\tif (this.outlineConnect && this.marker.highlight != null && this.marker.highlight.shape != null)
\t{
\t\tvar s = this.graph.view.scale;
\t\t
\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\tthis.constraintHandler.currentFocus != null)
\t\t{
\t\t\tthis.marker.highlight.shape.stroke = (outline) ? mxConstants.OUTLINE_HIGHLIGHT_COLOR : 'transparent';
\t\t\tthis.marker.highlight.shape.strokewidth = mxConstants.OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
\t\t\tthis.marker.highlight.repaint();
\t\t}
\t\telse if (this.marker.hasValidState())
\t\t{
\t\t\tthis.marker.highlight.shape.stroke = (this.graph.isCellConnectable(me.getCell()) &&
\t\t\t\tthis.marker.getValidState() != me.getState()) ?
\t\t\t\t'transparent' : mxConstants.DEFAULT_VALID_COLOR;
\t\t\tthis.marker.highlight.shape.strokewidth = mxConstants.HIGHLIGHT_STROKEWIDTH / s / s;
\t\t\tthis.marker.highlight.repaint();
\t\t}
\t}
\t
\tif (this.isSource)
\t{
\t\tsourceConstraint = constraint;
\t}
\telse if (this.isTarget)
\t{
\t\ttargetConstraint = constraint;
\t}
\t
\tif (this.isSource || this.isTarget)
\t{
\t\tif (constraint != null && constraint.point != null)
\t\t{
\t\t\tedge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X] = constraint.point.x;
\t\t\tedge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y] = constraint.point.y;
\t\t}
\t\telse
\t\t{
\t\t\tdelete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];
\t\t\tdelete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
\t\t}
\t}
\t
\tedge.setVisibleTerminalState(sourceState, true);
\tedge.setVisibleTerminalState(targetState, false);
\t
\tif (!this.isSource || sourceState != null)
\t{
\t\tedge.view.updateFixedTerminalPoint(edge, sourceState, true, sourceConstraint);
\t}
\t
\tif (!this.isTarget || targetState != null)
\t{
\t\tedge.view.updateFixedTerminalPoint(edge, targetState, false, targetConstraint);
\t}
\t
\tif ((this.isSource || this.isTarget) && terminalState == null)
\t{
\t\tedge.setAbsoluteTerminalPoint(point, this.isSource);

\t\tif (this.marker.getMarkedState() == null)
\t\t{
\t\t\tthis.error = (this.graph.allowDanglingEdges) ? null : '';
\t\t}
\t}
\t
\tedge.view.updatePoints(edge, this.points, sourceState, targetState);
\tedge.view.updateFloatingTerminalPoints(edge, sourceState, targetState);
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the preview.
 */
mxEdgeHandler.prototype.mouseMove = function(sender, me)
{
\tif (this.index != null && this.marker != null)
\t{
\t\tthis.currentPoint = this.getPointForEvent(me);
\t\tthis.error = null;
\t\t
\t\t// Uses the current point from the constraint handler if available
\t\tif (!this.graph.isIgnoreTerminalEvent(me.getEvent()) && mxEvent.isShiftDown(me.getEvent()) && this.snapPoint != null)
\t\t{
\t\t\tif (Math.abs(this.snapPoint.x - this.currentPoint.x) < Math.abs(this.snapPoint.y - this.currentPoint.y))
\t\t\t{
\t\t\t\tthis.currentPoint.x = this.snapPoint.x;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.currentPoint.y = this.snapPoint.y;
\t\t\t}
\t\t}
\t\t
\t\tif (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
\t\t{
\t\t\tif (this.customHandles != null)
\t\t\t{
\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - this.index].processEvent(me);
\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - this.index].positionChanged();
\t\t\t\t
\t\t\t\tif (this.shape != null && this.shape.node != null)
\t\t\t\t{
\t\t\t\t\tthis.shape.node.style.display = 'none';
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (this.isLabel)
\t\t{
\t\t\tthis.label.x = this.currentPoint.x;
\t\t\tthis.label.y = this.currentPoint.y;
\t\t}
\t\telse
\t\t{
\t\t\tthis.points = this.getPreviewPoints(this.currentPoint, me);
\t\t\tvar terminalState = (this.isSource || this.isTarget) ? this.getPreviewTerminalState(me) : null;
\t\t\t
\t\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\t\tthis.constraintHandler.currentFocus != null &&
\t\t\t\tthis.constraintHandler.currentPoint != null)
\t\t\t{
\t\t\t\tthis.currentPoint = this.constraintHandler.currentPoint.clone();
\t\t\t}
\t\t\telse if (this.outlineConnect)
\t\t\t{
\t\t\t\t// Need to check outline before cloning terminal state
\t\t\t\tvar outline = (this.isSource || this.isTarget) ? this.isOutlineConnectEvent(me) : false
\t\t\t\t\t\t
\t\t\t\tif (outline)
\t\t\t\t{
\t\t\t\t\tterminalState = this.marker.highlight.state;
\t\t\t\t}
\t\t\t\telse if (terminalState != null && terminalState != me.getState() &&
\t\t\t\t\tthis.graph.isCellConnectable(me.getCell()) &&
\t\t\t\t\tthis.marker.highlight.shape != null)
\t\t\t\t{
\t\t\t\t\tthis.marker.highlight.shape.stroke = 'transparent';
\t\t\t\t\tthis.marker.highlight.repaint();
\t\t\t\t\tterminalState = null;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (terminalState != null && !this.isCellEnabled(terminalState.cell))
\t\t\t{
\t\t\t\tterminalState = null;
\t\t\t\tthis.marker.reset();
\t\t\t}
\t\t\t
\t\t\tvar clone = this.clonePreviewState(this.currentPoint, (terminalState != null) ? terminalState.cell : null);
\t\t\tthis.updatePreviewState(clone, this.currentPoint, terminalState, me, outline);

\t\t\t// Sets the color of the preview to valid or invalid, updates the
\t\t\t// points of the preview and redraws
\t\t\tvar color = (this.error == null) ? this.marker.validColor : this.marker.invalidColor;
\t\t\tthis.setPreviewColor(color);
\t\t\tthis.abspoints = clone.absolutePoints;
\t\t\tthis.active = true;
\t\t\tthis.updateHint(me, this.currentPoint);
\t\t}

\t\t// This should go before calling isOutlineConnectEvent above. As a workaround
\t\t// we add an offset of gridSize to the hint to avoid problem with hit detection
\t\t// in highlight.isHighlightAt (which uses comonentFromPoint)
\t\tthis.drawPreview();
\t\tmxEvent.consume(me.getEvent());
\t\tme.consume();
\t}
\t// Workaround for disabling the connect highlight when over handle
\telse if (mxClient.IS_IE && this.getHandleForEvent(me) != null)
\t{
\t\tme.consume(false);
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event to applying the previewed changes on the edge by
 * using <moveLabel>, <connect> or <changePoints>.
 */
mxEdgeHandler.prototype.mouseUp = function(sender, me)
{
\t// Workaround for wrong event source in Webkit
\tif (this.index != null && this.marker != null)
\t{
\t\tif (this.shape != null && this.shape.node != null)
\t\t{
\t\t\tthis.shape.node.style.display = '';
\t\t}
\t\t
\t\tvar edge = this.state.cell;
\t\tvar index = this.index;
\t\tthis.index = null;

\t\t// Ignores event if mouse has not been moved
\t\tif (me.getX() != this.startX || me.getY() != this.startY)
\t\t{
\t\t\tvar clone = !this.graph.isIgnoreTerminalEvent(me.getEvent()) && this.graph.isCloneEvent(me.getEvent()) &&
\t\t\t\tthis.cloneEnabled && this.graph.isCellsCloneable();
\t\t\t
\t\t\t// Displays the reason for not carriying out the change
\t\t\t// if there is an error message with non-zero length
\t\t\tif (this.error != null)
\t\t\t{
\t\t\t\tif (this.error.length > 0)
\t\t\t\t{
\t\t\t\t\tthis.graph.validationAlert(this.error);
\t\t\t\t}
\t\t\t}
\t\t\telse if (index <= mxEvent.CUSTOM_HANDLE && index > mxEvent.VIRTUAL_HANDLE)
\t\t\t{
\t\t\t\tif (this.customHandles != null)
\t\t\t\t{
\t\t\t\t\tvar model = this.graph.getModel();
\t\t\t\t\t
\t\t\t\t\tmodel.beginUpdate();
\t\t\t\t\ttry
\t\t\t\t\t{
\t\t\t\t\t\tthis.customHandles[mxEvent.CUSTOM_HANDLE - index].execute(me);
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\tif (this.shape != null && this.shape.node != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.shape.apply(this.state);
\t\t\t\t\t\t\tthis.shape.redraw();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tfinally
\t\t\t\t\t{
\t\t\t\t\t\tmodel.endUpdate();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\telse if (this.isLabel)
\t\t\t{
\t\t\t\tthis.moveLabel(this.state, this.label.x, this.label.y);
\t\t\t}
\t\t\telse if (this.isSource || this.isTarget)
\t\t\t{
\t\t\t\tvar terminal = null;
\t\t\t\t
\t\t\t\tif (this.constraintHandler.currentConstraint != null &&
\t\t\t\t\tthis.constraintHandler.currentFocus != null)
\t\t\t\t{
\t\t\t\t\tterminal = this.constraintHandler.currentFocus.cell;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (terminal == null && this.marker.hasValidState() && this.marker.highlight != null &&
\t\t\t\t\tthis.marker.highlight.shape != null &&
\t\t\t\t\tthis.marker.highlight.shape.stroke != 'transparent' &&
\t\t\t\t\tthis.marker.highlight.shape.stroke != 'white')
\t\t\t\t{
\t\t\t\t\tterminal = this.marker.validState.cell;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (terminal != null)
\t\t\t\t{
\t\t\t\t\tvar model = this.graph.getModel();
\t\t\t\t\tvar parent = model.getParent(edge);
\t\t\t\t\t
\t\t\t\t\tmodel.beginUpdate();
\t\t\t\t\ttry
\t\t\t\t\t{
\t\t\t\t\t\t// Clones and adds the cell
\t\t\t\t\t\tif (clone)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar geo = model.getGeometry(edge);
\t\t\t\t\t\t\tvar clone = this.graph.cloneCell(edge);
\t\t\t\t\t\t\tmodel.add(parent, clone, model.getChildCount(parent));
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (geo != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tgeo = geo.clone();
\t\t\t\t\t\t\t\tmodel.setGeometry(clone, geo);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar other = model.getTerminal(edge, !this.isSource);
\t\t\t\t\t\t\tthis.graph.connectCell(clone, other, !this.isSource);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tedge = clone;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tedge = this.connect(edge, terminal, this.isSource, clone, me);
\t\t\t\t\t}
\t\t\t\t\tfinally
\t\t\t\t\t{
\t\t\t\t\t\tmodel.endUpdate();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse if (this.graph.isAllowDanglingEdges())
\t\t\t\t{
\t\t\t\t\tvar pt = this.abspoints[(this.isSource) ? 0 : this.abspoints.length - 1];
\t\t\t\t\tpt.x = this.roundLength(pt.x / this.graph.view.scale - this.graph.view.translate.x);
\t\t\t\t\tpt.y = this.roundLength(pt.y / this.graph.view.scale - this.graph.view.translate.y);

\t\t\t\t\tvar pstate = this.graph.getView().getState(
\t\t\t\t\t\t\tthis.graph.getModel().getParent(edge));
\t\t\t\t\t\t\t
\t\t\t\t\tif (pstate != null)
\t\t\t\t\t{
\t\t\t\t\t\tpt.x -= pstate.origin.x;
\t\t\t\t\t\tpt.y -= pstate.origin.y;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tpt.x -= this.graph.panDx / this.graph.view.scale;
\t\t\t\t\tpt.y -= this.graph.panDy / this.graph.view.scale;
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t// Destroys and recreates this handler
\t\t\t\t\tedge = this.changeTerminalPoint(edge, pt, this.isSource, clone);
\t\t\t\t}
\t\t\t}
\t\t\telse if (this.active)
\t\t\t{
\t\t\t\tedge = this.changePoints(edge, this.points, clone);
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.graph.getView().invalidate(this.state.cell);
\t\t\t\tthis.graph.getView().validate(this.state.cell);\t\t\t\t\t\t
\t\t\t}
\t\t}
\t\telse if (this.graph.isToggleEvent(me.getEvent()))
\t\t{
\t\t\tthis.graph.selectCellForEvent(this.state.cell, me.getEvent());
\t\t}

\t\t// Resets the preview color the state of the handler if this
\t\t// handler has not been recreated
\t\tif (this.marker != null)
\t\t{
\t\t\tthis.reset();

\t\t\t// Updates the selection if the edge has been cloned
\t\t\tif (edge != this.state.cell)
\t\t\t{
\t\t\t\tthis.graph.setSelectionCell(edge);
\t\t\t}
\t\t}

\t\tme.consume();
\t}
};

/**
 * Function: reset
 * 
 * Resets the state of this handler.
 */
mxEdgeHandler.prototype.reset = function()
{
\tif (this.active)
\t{
\t\tthis.refresh();
\t}
\t
\tthis.error = null;
\tthis.index = null;
\tthis.label = null;
\tthis.points = null;
\tthis.snapPoint = null;
\tthis.isLabel = false;
\tthis.isSource = false;
\tthis.isTarget = false;
\tthis.active = false;
\t
\tif (this.livePreview && this.sizers != null)
\t{
\t\tfor (var i = 0; i < this.sizers.length; i++)
\t\t{
\t\t\tif (this.sizers[i] != null)
\t\t\t{
\t\t\t\tthis.sizers[i].node.style.display = '';
\t\t\t}
\t\t}
\t}

\tif (this.marker != null)
\t{
\t\tthis.marker.reset();
\t}
\t
\tif (this.constraintHandler != null)
\t{
\t\tthis.constraintHandler.reset();
\t}
\t
\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tthis.customHandles[i].reset();
\t\t}
\t}

\tthis.setPreviewColor(mxConstants.EDGE_SELECTION_COLOR);
\tthis.removeHint();
\tthis.redraw();
};

/**
 * Function: setPreviewColor
 * 
 * Sets the color of the preview to the given value.
 */
mxEdgeHandler.prototype.setPreviewColor = function(color)
{
\tif (this.shape != null)
\t{
\t\tthis.shape.stroke = color;
\t}
};


/**
 * Function: convertPoint
 * 
 * Converts the given point in-place from screen to unscaled, untranslated
 * graph coordinates and applies the grid. Returns the given, modified
 * point instance.
 * 
 * Parameters:
 * 
 * point - <mxPoint> to be converted.
 * gridEnabled - Boolean that specifies if the grid should be applied.
 */
mxEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
{
\tvar scale = this.graph.getView().getScale();
\tvar tr = this.graph.getView().getTranslate();
\t\t
\tif (gridEnabled)
\t{
\t\tpoint.x = this.graph.snap(point.x);
\t\tpoint.y = this.graph.snap(point.y);
\t}
\t
\tpoint.x = Math.round(point.x / scale - tr.x);
\tpoint.y = Math.round(point.y / scale - tr.y);

\tvar pstate = this.graph.getView().getState(
\t\tthis.graph.getModel().getParent(this.state.cell));

\tif (pstate != null)
\t{
\t\tpoint.x -= pstate.origin.x;
\t\tpoint.y -= pstate.origin.y;
\t}

\treturn point;
};

/**
 * Function: moveLabel
 * 
 * Changes the coordinates for the label of the given edge.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge.
 * x - Integer that specifies the x-coordinate of the new location.
 * y - Integer that specifies the y-coordinate of the new location.
 */
mxEdgeHandler.prototype.moveLabel = function(edgeState, x, y)
{
\tvar model = this.graph.getModel();
\tvar geometry = model.getGeometry(edgeState.cell);
\t
\tif (geometry != null)
\t{
\t\tvar scale = this.graph.getView().scale;
\t\tgeometry = geometry.clone();
\t\t
\t\tif (geometry.relative)
\t\t{
\t\t\t// Resets the relative location stored inside the geometry
\t\t\tvar pt = this.graph.getView().getRelativePoint(edgeState, x, y);
\t\t\tgeometry.x = Math.round(pt.x * 10000) / 10000;
\t\t\tgeometry.y = Math.round(pt.y);
\t\t\t
\t\t\t// Resets the offset inside the geometry to find the offset
\t\t\t// from the resulting point
\t\t\tgeometry.offset = new mxPoint(0, 0);
\t\t\tvar pt = this.graph.view.getPoint(edgeState, geometry);
\t\t\tgeometry.offset = new mxPoint(Math.round((x - pt.x) / scale), Math.round((y - pt.y) / scale));
\t\t}
\t\telse
\t\t{
\t\t\tvar points = edgeState.absolutePoints;
\t\t\tvar p0 = points[0];
\t\t\tvar pe = points[points.length - 1];
\t\t\t
\t\t\tif (p0 != null && pe != null)
\t\t\t{
\t\t\t\tvar cx = p0.x + (pe.x - p0.x) / 2;
\t\t\t\tvar cy = p0.y + (pe.y - p0.y) / 2;
\t\t\t\t
\t\t\t\tgeometry.offset = new mxPoint(Math.round((x - cx) / scale), Math.round((y - cy) / scale));
\t\t\t\tgeometry.x = 0;
\t\t\t\tgeometry.y = 0;
\t\t\t}
\t\t}

\t\tmodel.setGeometry(edgeState.cell, geometry);
\t}
};

/**
 * Function: connect
 * 
 * Changes the terminal or terminal point of the given edge in the graph
 * model.
 * 
 * Parameters:
 * 
 * edge - <mxCell> that represents the edge to be reconnected.
 * terminal - <mxCell> that represents the new terminal.
 * isSource - Boolean indicating if the new terminal is the source or
 * target terminal.
 * isClone - Boolean indicating if the new connection should be a clone of
 * the old edge.
 * me - <mxMouseEvent> that contains the mouse up event.
 */
mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
{
\tvar model = this.graph.getModel();
\tvar parent = model.getParent(edge);
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tvar constraint = this.constraintHandler.currentConstraint;
\t\t
\t\tif (constraint == null)
\t\t{
\t\t\tconstraint = new mxConnectionConstraint();
\t\t}

\t\tthis.graph.connectCell(edge, terminal, isSource, constraint);
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
\t
\treturn edge;
};

/**
 * Function: changeTerminalPoint
 * 
 * Changes the terminal point of the given edge.
 */
mxEdgeHandler.prototype.changeTerminalPoint = function(edge, point, isSource, clone)
{
\tvar model = this.graph.getModel();

\tmodel.beginUpdate();
\ttry
\t{
\t\tif (clone)
\t\t{
\t\t\tvar parent = model.getParent(edge);
\t\t\tvar terminal = model.getTerminal(edge, !isSource);
\t\t\tedge = this.graph.cloneCell(edge);
\t\t\tmodel.add(parent, edge, model.getChildCount(parent));
\t\t\tmodel.setTerminal(edge, terminal, !isSource);
\t\t}

\t\tvar geo = model.getGeometry(edge);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tgeo = geo.clone();
\t\t\tgeo.setTerminalPoint(point, isSource);
\t\t\tmodel.setGeometry(edge, geo);
\t\t\tthis.graph.connectCell(edge, null, isSource, new mxConnectionConstraint());
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
\t
\treturn edge;
};

/**
 * Function: changePoints
 * 
 * Changes the control points of the given edge in the graph model.
 */
mxEdgeHandler.prototype.changePoints = function(edge, points, clone)
{
\tvar model = this.graph.getModel();
\tmodel.beginUpdate();
\ttry
\t{
\t\tif (clone)
\t\t{
\t\t\tvar parent = model.getParent(edge);
\t\t\tvar source = model.getTerminal(edge, true);
\t\t\tvar target = model.getTerminal(edge, false);
\t\t\tedge = this.graph.cloneCell(edge);
\t\t\tmodel.add(parent, edge, model.getChildCount(parent));
\t\t\tmodel.setTerminal(edge, source, true);
\t\t\tmodel.setTerminal(edge, target, false);
\t\t}
\t\t
\t\tvar geo = model.getGeometry(edge);
\t\t
\t\tif (geo != null)
\t\t{
\t\t\tgeo = geo.clone();
\t\t\tgeo.points = points;
\t\t\t
\t\t\tmodel.setGeometry(edge, geo);
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
\t
\treturn edge;
};

/**
 * Function: addPoint
 * 
 * Adds a control point for the given state and event.
 */
mxEdgeHandler.prototype.addPoint = function(state, evt)
{
\tvar pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt),
\t\t\tmxEvent.getClientY(evt));
\tvar gridEnabled = this.graph.isGridEnabledEvent(evt);
\tthis.convertPoint(pt, gridEnabled);
\tthis.addPointAt(state, pt.x, pt.y);
\tmxEvent.consume(evt);
};

/**
 * Function: addPointAt
 * 
 * Adds a control point at the given point.
 */
mxEdgeHandler.prototype.addPointAt = function(state, x, y)
{
\tvar geo = this.graph.getCellGeometry(state.cell);
\tvar pt = new mxPoint(x, y);
\t
\tif (geo != null)
\t{
\t\tgeo = geo.clone();
\t\tvar t = this.graph.view.translate;
\t\tvar s = this.graph.view.scale;
\t\tvar offset = new mxPoint(t.x * s, t.y * s);
\t\t
\t\tvar parent = this.graph.model.getParent(this.state.cell);
\t\t
\t\tif (this.graph.model.isVertex(parent))
\t\t{
\t\t\tvar pState = this.graph.view.getState(parent);
\t\t\toffset = new mxPoint(pState.x, pState.y);
\t\t}
\t\t
\t\tvar index = mxUtils.findNearestSegment(state, pt.x * s + offset.x, pt.y * s + offset.y);

\t\tif (geo.points == null)
\t\t{
\t\t\tgeo.points = [pt];
\t\t}
\t\telse
\t\t{
\t\t\tgeo.points.splice(index, 0, pt);
\t\t}
\t\t
\t\tthis.graph.getModel().setGeometry(state.cell, geo);
\t\tthis.refresh();\t
\t\tthis.redraw();
\t}
};

/**
 * Function: removePoint
 * 
 * Removes the control point at the given index from the given state.
 */
mxEdgeHandler.prototype.removePoint = function(state, index)
{
\tif (index > 0 && index < this.abspoints.length - 1)
\t{
\t\tvar geo = this.graph.getCellGeometry(this.state.cell);
\t\t
\t\tif (geo != null && geo.points != null)
\t\t{
\t\t\tgeo = geo.clone();
\t\t\tgeo.points.splice(index - 1, 1);
\t\t\tthis.graph.getModel().setGeometry(state.cell, geo);
\t\t\tthis.refresh();
\t\t\tthis.redraw();
\t\t}
\t}
};

/**
 * Function: getHandleFillColor
 * 
 * Returns the fillcolor for the handle at the given index.
 */
mxEdgeHandler.prototype.getHandleFillColor = function(index)
{
\tvar isSource = index == 0;
\tvar cell = this.state.cell;
\tvar terminal = this.graph.getModel().getTerminal(cell, isSource);
\tvar color = mxConstants.HANDLE_FILLCOLOR;
\t
\tif ((terminal != null && !this.graph.isCellDisconnectable(cell, terminal, isSource)) ||
\t\t(terminal == null && !this.graph.isTerminalPointMovable(cell, isSource)))
\t{
\t\tcolor = mxConstants.LOCKED_HANDLE_FILLCOLOR;
\t}
\telse if (terminal != null && this.graph.isCellDisconnectable(cell, terminal, isSource))
\t{
\t\tcolor = mxConstants.CONNECT_HANDLE_FILLCOLOR;
\t}
\t
\treturn color;
};

/**
 * Function: redraw
 * 
 * Redraws the preview, and the bends- and label control points.
 */
mxEdgeHandler.prototype.redraw = function(ignoreHandles)
{
\tif (this.state != null)
\t{
\t\tthis.abspoints = this.state.absolutePoints.slice();
\t\tvar g = this.graph.getModel().getGeometry(this.state.cell);
\t\t
\t\tif (g != null)
\t\t{
\t\t\tvar pts = g.points;
\t\t
\t\t\tif (this.bends != null && this.bends.length > 0)
\t\t\t{
\t\t\t\tif (pts != null)
\t\t\t\t{
\t\t\t\t\tif (this.points == null)
\t\t\t\t\t{
\t\t\t\t\t\tthis.points = [];
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tfor (var i = 1; i < this.bends.length - 1; i++)
\t\t\t\t\t{
\t\t\t\t\t\tif (this.bends[i] != null && this.abspoints[i] != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tthis.points[i - 1] = pts[i - 1];
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tthis.drawPreview();
\t\t
\t\tif (!ignoreHandles)
\t\t{
\t\t\tthis.redrawHandles();
\t\t}
\t}
};

/**
 * Function: redrawHandles
 * 
 * Redraws the handles.
 */
mxEdgeHandler.prototype.redrawHandles = function()
{
\tvar cell = this.state.cell;

\t// Updates the handle for the label position
\tvar b = this.labelShape.bounds;
\tthis.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
\tthis.labelShape.bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
\t\tMath.round(this.label.y - b.height / 2), b.width, b.height);

\t// Shows or hides the label handle depending on the label
\tvar lab = this.graph.getLabel(cell);
\tthis.labelShape.visible = (lab != null && lab.length > 0 && this.graph.isLabelMovable(cell));
\t
\tif (this.bends != null && this.bends.length > 0)
\t{
\t\tvar n = this.abspoints.length - 1;
\t\t
\t\tvar p0 = this.abspoints[0];
\t\tvar x0 = p0.x;
\t\tvar y0 = p0.y;
\t\t
\t\tb = this.bends[0].bounds;
\t\tthis.bends[0].bounds = new mxRectangle(Math.floor(x0 - b.width / 2),
\t\t\t\tMath.floor(y0 - b.height / 2), b.width, b.height);
\t\tthis.bends[0].fill = this.getHandleFillColor(0);
\t\tthis.bends[0].redraw();
\t\t
\t\tif (this.manageLabelHandle)
\t\t{
\t\t\tthis.checkLabelHandle(this.bends[0].bounds);
\t\t}
\t\t\t\t
\t\tvar pe = this.abspoints[n];
\t\tvar xn = pe.x;
\t\tvar yn = pe.y;
\t\t
\t\tvar bn = this.bends.length - 1;
\t\tb = this.bends[bn].bounds;
\t\tthis.bends[bn].bounds = new mxRectangle(Math.floor(xn - b.width / 2),
\t\t\t\tMath.floor(yn - b.height / 2), b.width, b.height);
\t\tthis.bends[bn].fill = this.getHandleFillColor(bn);
\t\tthis.bends[bn].redraw();
\t\t\t\t
\t\tif (this.manageLabelHandle)
\t\t{
\t\t\tthis.checkLabelHandle(this.bends[bn].bounds);
\t\t}
\t\t
\t\tthis.redrawInnerBends(p0, pe);
\t}

\tif (this.abspoints != null && this.virtualBends != null && this.virtualBends.length > 0)
\t{
\t\tvar last = this.abspoints[0];
\t\t
\t\tfor (var i = 0; i < this.virtualBends.length; i++)
\t\t{
\t\t\tif (this.virtualBends[i] != null && this.abspoints[i + 1] != null)
\t\t\t{
\t\t\t\tvar pt = this.abspoints[i + 1];
\t\t\t\tvar b = this.virtualBends[i];
\t\t\t\tvar x = last.x + (pt.x - last.x) / 2;
\t\t\t\tvar y = last.y + (pt.y - last.y) / 2;
\t\t\t\tb.bounds = new mxRectangle(Math.floor(x - b.bounds.width / 2),
\t\t\t\t\t\tMath.floor(y - b.bounds.height / 2), b.bounds.width, b.bounds.height);
\t\t\t\tb.redraw();
\t\t\t\tmxUtils.setOpacity(b.node, this.virtualBendOpacity);
\t\t\t\tlast = pt;
\t\t\t\t
\t\t\t\tif (this.manageLabelHandle)
\t\t\t\t{
\t\t\t\t\tthis.checkLabelHandle(b.bounds);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\tif (this.labelShape != null)
\t{
\t\tthis.labelShape.redraw();
\t}
\t
\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tvar temp = this.customHandles[i].shape.node.style.display;
\t\t\tthis.customHandles[i].redraw();
\t\t\tthis.customHandles[i].shape.node.style.display = temp;

\t\t\t// Hides custom handles during text editing
\t\t\tthis.customHandles[i].shape.node.style.visibility =
\t\t\t\t(this.isCustomHandleVisible(this.customHandles[i])) ?
\t\t\t\t'' : 'hidden';
\t\t}
\t}
};

/**
 * Function: isCustomHandleVisible
 * 
 * Returns true if the given custom handle is visible.
 */
mxEdgeHandler.prototype.isCustomHandleVisible = function(handle)
{
\treturn !this.graph.isEditing() && this.state.view.graph.getSelectionCount() == 1;
};

/**
 * Function: hideHandles
 * 
 * Shortcut to <hideSizers>.
 */
mxEdgeHandler.prototype.setHandlesVisible = function(visible)
{
\tif (this.bends != null)
\t{
\t\tfor (var i = 0; i < this.bends.length; i++)
\t\t{
\t\t\tthis.bends[i].node.style.display = (visible) ? '' : 'none';
\t\t}
\t}
\t
\tif (this.virtualBends != null)
\t{
\t\tfor (var i = 0; i < this.virtualBends.length; i++)
\t\t{
\t\t\tthis.virtualBends[i].node.style.display = (visible) ? '' : 'none';
\t\t}
\t}

\tif (this.labelShape != null)
\t{
\t\tthis.labelShape.node.style.display = (visible) ? '' : 'none';
\t}
\t
\tif (this.customHandles != null)
\t{
\t\tfor (var i = 0; i < this.customHandles.length; i++)
\t\t{
\t\t\tthis.customHandles[i].setVisible(visible);
\t\t}
\t}
};

/**
 * Function: redrawInnerBends
 * 
 * Updates and redraws the inner bends.
 * 
 * Parameters:
 * 
 * p0 - <mxPoint> that represents the location of the first point.
 * pe - <mxPoint> that represents the location of the last point.
 */
mxEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
{
\tfor (var i = 1; i < this.bends.length - 1; i++)
\t{
\t\tif (this.bends[i] != null)
\t\t{
\t\t\tif (this.abspoints[i] != null)
\t\t\t{
\t\t\t\tvar x = this.abspoints[i].x;
\t\t\t\tvar y = this.abspoints[i].y;
\t\t\t\t
\t\t\t\tvar b = this.bends[i].bounds;
\t\t\t\tthis.bends[i].node.style.visibility = 'visible';
\t\t\t\tthis.bends[i].bounds = new mxRectangle(Math.round(x - b.width / 2),
\t\t\t\t\t\tMath.round(y - b.height / 2), b.width, b.height);
\t\t\t\t
\t\t\t\tif (this.manageLabelHandle)
\t\t\t\t{
\t\t\t\t\tthis.checkLabelHandle(this.bends[i].bounds);
\t\t\t\t}
\t\t\t\telse if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(this.bends[i].bounds, this.labelShape.bounds))
\t\t\t\t{
\t\t\t\t\tw = mxConstants.HANDLE_SIZE + 3;
\t\t\t\t\th = mxConstants.HANDLE_SIZE + 3;
\t\t\t\t\tthis.bends[i].bounds = new mxRectangle(Math.round(x - w / 2), Math.round(y - h / 2), w, h);
\t\t\t\t}
\t\t\t\t
\t\t\t\tthis.bends[i].redraw();
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.bends[i].destroy();
\t\t\t\tthis.bends[i] = null;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: checkLabelHandle
 * 
 * Checks if the label handle intersects the given bounds and moves it if it
 * intersects.
 */
mxEdgeHandler.prototype.checkLabelHandle = function(b)
{
\tif (this.labelShape != null)
\t{
\t\tvar b2 = this.labelShape.bounds;
\t\t
\t\tif (mxUtils.intersects(b, b2))
\t\t{
\t\t\tif (b.getCenterY() < b2.getCenterY())
\t\t\t{
\t\t\t\tb2.y = b.y + b.height;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tb2.y = b.y - b2.height;
\t\t\t}
\t\t}
\t}
};

/**
 * Function: drawPreview
 * 
 * Redraws the preview.
 */
mxEdgeHandler.prototype.drawPreview = function()
{
\ttry
\t{
\t\tif (this.isLabel)
\t\t{
\t\t\tvar b = this.labelShape.bounds;
\t\t\tvar bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
\t\t\t\tMath.round(this.label.y - b.height / 2), b.width, b.height);
\t\t\t
\t\t\tif (!this.labelShape.bounds.equals(bounds))
\t\t\t{
\t\t\t\tthis.labelShape.bounds = bounds;
\t\t\t\tthis.labelShape.redraw();
\t\t\t}
\t\t}
\t\t
\t\tif (this.shape != null && !mxUtils.equalPoints(this.shape.points, this.abspoints))
\t\t{
\t\t\tthis.shape.apply(this.state);
\t\t\tthis.shape.points = this.abspoints.slice();
\t\t\tthis.shape.scale = this.state.view.scale;
\t\t\tthis.shape.isDashed = this.isSelectionDashed();
\t\t\tthis.shape.stroke = this.getSelectionColor();
\t\t\tthis.shape.strokewidth = this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale;
\t\t\tthis.shape.isShadow = false;
\t\t\tthis.shape.redraw();
\t\t}
\t\t
\t\tthis.updateParentHighlight();
\t}
\tcatch (e)
\t{
\t\t// ignore
\t}
};

/**
 * Function: refresh
 * 
 * Refreshes the bends of this handler.
 */
mxEdgeHandler.prototype.refresh = function()
{
\tif (this.state != null)
\t{
\t\tthis.abspoints = this.getSelectionPoints(this.state);
\t\tthis.points = [];
\t
\t\tif (this.bends != null)
\t\t{
\t\t\tthis.destroyBends(this.bends);
\t\t\tthis.bends = this.createBends();
\t\t}
\t\t
\t\tif (this.virtualBends != null)
\t\t{
\t\t\tthis.destroyBends(this.virtualBends);
\t\t\tthis.virtualBends = this.createVirtualBends();
\t\t}
\t\t
\t\tif (this.customHandles != null)
\t\t{
\t\t\tthis.destroyBends(this.customHandles);
\t\t\tthis.customHandles = this.createCustomHandles();
\t\t}
\t\t
\t\t// Puts label node on top of bends
\t\tif (this.labelShape != null && this.labelShape.node != null && this.labelShape.node.parentNode != null)
\t\t{
\t\t\tthis.labelShape.node.parentNode.appendChild(this.labelShape.node);
\t\t}
\t}
};

/**
 * Function: isDestroyed
 * 
 * Returns true if <destroy> was called.
 */
mxEdgeHandler.prototype.isDestroyed = function()
{
\treturn this.shape == null;
};

/**
 * Function: destroyBends
 * 
 * Destroys all elements in <bends>.
 */
mxEdgeHandler.prototype.destroyBends = function(bends)
{
\tif (bends != null)
\t{
\t\tfor (var i = 0; i < bends.length; i++)
\t\t{
\t\t\tif (bends[i] != null)
\t\t\t{
\t\t\t\tbends[i].destroy();
\t\t\t}
\t\t}
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes. This does
 * normally not need to be called as handlers are destroyed automatically
 * when the corresponding cell is deselected.
 */
mxEdgeHandler.prototype.destroy = function()
{
\tif (this.escapeHandler != null)
\t{
\t\tthis.state.view.graph.removeListener(this.escapeHandler);
\t\tthis.escapeHandler = null;
\t}
\t
\tif (this.marker != null)
\t{
\t\tthis.marker.destroy();
\t\tthis.marker = null;
\t}
\t
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
\t
\tif (this.parentHighlight != null)
\t{
\t\tvar parent = this.graph.model.getParent(this.state.cell);
\t\tvar pstate = this.graph.view.getState(parent);

\t\tif (pstate != null && pstate.parentHighlight == this.parentHighlight)
\t\t{
\t\t\tpstate.parentHighlight = null;
\t\t}
\t\t
\t\tthis.parentHighlight.destroy();
\t\tthis.parentHighlight = null;
\t}
\t
\tif (this.labelShape != null)
\t{
\t\tthis.labelShape.destroy();
\t\tthis.labelShape = null;
\t}

\tif (this.constraintHandler != null)
\t{
\t\tthis.constraintHandler.destroy();
\t\tthis.constraintHandler = null;
\t}
\t
\tthis.destroyBends(this.virtualBends);
\tthis.virtualBends = null;
\t
\tthis.destroyBends(this.customHandles);
\tthis.customHandles = null;

\tthis.destroyBends(this.bends);
\tthis.bends = null;
\t
\tthis.removeHint();
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxElbowEdgeHandler
 *
 * Graph event handler that reconnects edges and modifies control points and
 * the edge label location. Uses <mxTerminalMarker> for finding and
 * highlighting new source and target vertices. This handler is automatically
 * created in <mxGraph.createHandler>. It extends <mxEdgeHandler>.
 * 
 * Constructor: mxEdgeHandler
 *
 * Constructs an edge handler for the specified <mxCellState>.
 * 
 * Parameters:
 * 
 * state - <mxCellState> of the cell to be modified.
 */
function mxElbowEdgeHandler(state)
{
\tmxEdgeHandler.call(this, state);
};

/**
 * Extends mxEdgeHandler.
 */
mxUtils.extend(mxElbowEdgeHandler, mxEdgeHandler);

/**
 * Specifies if a double click on the middle handle should call
 * <mxGraph.flipEdge>. Default is true.
 */
mxElbowEdgeHandler.prototype.flipEnabled = true;

/**
 * Variable: doubleClickOrientationResource
 * 
 * Specifies the resource key for the tooltip to be displayed on the single
 * control point for routed edges. If the resource for this key does not
 * exist then the value is used as the error message. Default is
 * 'doubleClickOrientation'.
 */
mxElbowEdgeHandler.prototype.doubleClickOrientationResource =
\t(mxClient.language != 'none') ? 'doubleClickOrientation' : '';

/**
 * Function: createBends
 * 
 * Overrides <mxEdgeHandler.createBends> to create custom bends.
 */
 mxElbowEdgeHandler.prototype.createBends = function()
 {
\tvar bends = [];
\t
\t// Source
\tvar bend = this.createHandleShape(0);
\tthis.initBend(bend);
\tbend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
\tbends.push(bend);

\t// Virtual
\tbends.push(this.createVirtualBend(mxUtils.bind(this, function(evt)
\t{
\t\tif (!mxEvent.isConsumed(evt) && this.flipEnabled)
\t\t{
\t\t\tthis.graph.flipEdge(this.state.cell, evt);
\t\t\tmxEvent.consume(evt);
\t\t}
\t})));
\t
\tthis.points.push(new mxPoint(0,0));

\t// Target
\tbend = this.createHandleShape(2);
\tthis.initBend(bend);
\tbend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
\tbends.push(bend);
\t
\treturn bends;
 };

/**
 * Function: createVirtualBend
 * 
 * Creates a virtual bend that supports double clicking and calls
 * <mxGraph.flipEdge>.
 */
mxElbowEdgeHandler.prototype.createVirtualBend = function(dblClickHandler)
{
\tvar bend = this.createHandleShape();
\tthis.initBend(bend, dblClickHandler);

\tbend.setCursor(this.getCursorForBend());

\tif (!this.graph.isCellBendable(this.state.cell))
\t{
\t\tbend.node.style.display = 'none';
\t}

\treturn bend;
};

/**
 * Function: getCursorForBend
 * 
 * Returns the cursor to be used for the bend.
 */
mxElbowEdgeHandler.prototype.getCursorForBend = function()
{
\treturn (this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.TopToBottom ||
\t\tthis.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_TOPTOBOTTOM ||
\t\t((this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.ElbowConnector ||
\t\tthis.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_ELBOW)&&
\t\tthis.state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) ? 
\t\t'row-resize' : 'col-resize';
};

/**
 * Function: getTooltipForNode
 * 
 * Returns the tooltip for the given node.
 */
mxElbowEdgeHandler.prototype.getTooltipForNode = function(node)
{
\tvar tip = null;
\t
\tif (this.bends != null && this.bends[1] != null && (node == this.bends[1].node ||
\t\tnode.parentNode == this.bends[1].node))
\t{
\t\ttip = this.doubleClickOrientationResource;
\t\ttip = mxResources.get(tip) || tip; // translate
\t}

\treturn tip;
};

/**
 * Function: convertPoint
 * 
 * Converts the given point in-place from screen to unscaled, untranslated
 * graph coordinates and applies the grid.
 * 
 * Parameters:
 * 
 * point - <mxPoint> to be converted.
 * gridEnabled - Boolean that specifies if the grid should be applied.
 */
mxElbowEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
{
\tvar scale = this.graph.getView().getScale();
\tvar tr = this.graph.getView().getTranslate();
\tvar origin = this.state.origin;
\t
\tif (gridEnabled)
\t{
\t\tpoint.x = this.graph.snap(point.x);
\t\tpoint.y = this.graph.snap(point.y);
\t}
\t
\tpoint.x = Math.round(point.x / scale - tr.x - origin.x);
\tpoint.y = Math.round(point.y / scale - tr.y - origin.y);
\t
\treturn point;
};

/**
 * Function: redrawInnerBends
 * 
 * Updates and redraws the inner bends.
 * 
 * Parameters:
 * 
 * p0 - <mxPoint> that represents the location of the first point.
 * pe - <mxPoint> that represents the location of the last point.
 */
mxElbowEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
{
\tvar g = this.graph.getModel().getGeometry(this.state.cell);
\tvar pts = this.state.absolutePoints;
\tvar pt = null;

\t// Keeps the virtual bend on the edge shape
\tif (pts.length > 1)
\t{
\t\tp0 = pts[1];
\t\tpe = pts[pts.length - 2];
\t}
\telse if (g.points != null && g.points.length > 0)
\t{
\t\tpt = pts[0];
\t}
\t
\tif (pt == null)
\t{
\t\tpt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
\t}
\telse
\t{
\t\tpt = new mxPoint(this.graph.getView().scale * (pt.x + this.graph.getView().translate.x + this.state.origin.x),
\t\t\t\tthis.graph.getView().scale * (pt.y + this.graph.getView().translate.y + this.state.origin.y));
\t}

\t// Makes handle slightly bigger if the yellow  label handle
\t// exists and intersects this green handle
\tvar b = this.bends[1].bounds;
\tvar w = b.width;
\tvar h = b.height;
\tvar bounds = new mxRectangle(Math.round(pt.x - w / 2), Math.round(pt.y - h / 2), w, h);

\tif (this.manageLabelHandle)
\t{
\t\tthis.checkLabelHandle(bounds);
\t}
\telse if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(bounds, this.labelShape.bounds))
\t{
\t\tw = mxConstants.HANDLE_SIZE + 3;
\t\th = mxConstants.HANDLE_SIZE + 3;
\t\tbounds = new mxRectangle(Math.floor(pt.x - w / 2), Math.floor(pt.y - h / 2), w, h);
\t}

\tthis.bends[1].bounds = bounds;
\tthis.bends[1].redraw();
\t
\tif (this.manageLabelHandle)
\t{
\t\tthis.checkLabelHandle(this.bends[1].bounds);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
function mxEdgeSegmentHandler(state)
{
\tmxEdgeHandler.call(this, state);
};

/**
 * Extends mxEdgeHandler.
 */
mxUtils.extend(mxEdgeSegmentHandler, mxElbowEdgeHandler);

/**
 * Function: getCurrentPoints
 * 
 * Returns the current absolute points.
 */
mxEdgeSegmentHandler.prototype.getCurrentPoints = function()
{
\tvar pts = this.state.absolutePoints;
\t
\tif (pts != null)
\t{
\t\t// Special case for straight edges where we add a virtual middle handle for moving the edge
\t\tvar tol = Math.max(1, this.graph.view.scale);
\t\t
\t\tif (pts.length == 2 || (pts.length == 3 &&
\t\t\t(Math.abs(pts[0].x - pts[1].x) < tol && Math.abs(pts[1].x - pts[2].x) < tol ||
\t\t\tMath.abs(pts[0].y - pts[1].y) < tol && Math.abs(pts[1].y - pts[2].y) < tol)))
\t\t{
\t\t\tvar cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
\t\t\tvar cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
\t\t\t
\t\t\tpts = [pts[0], new mxPoint(cx, cy), new mxPoint(cx, cy), pts[pts.length - 1]];\t
\t\t}
\t}

\treturn pts;
};

/**
 * Function: getPreviewPoints
 * 
 * Updates the given preview state taking into account the state of the constraint handler.
 */
mxEdgeSegmentHandler.prototype.getPreviewPoints = function(point)
{
\tif (this.isSource || this.isTarget)
\t{
\t\treturn mxElbowEdgeHandler.prototype.getPreviewPoints.apply(this, arguments);
\t}
\telse
\t{
\t\tvar pts = this.getCurrentPoints();
\t\tvar last = this.convertPoint(pts[0].clone(), false);
\t\tpoint = this.convertPoint(point.clone(), false);
\t\tvar result = [];

\t\tfor (var i = 1; i < pts.length; i++)
\t\t{
\t\t\tvar pt = this.convertPoint(pts[i].clone(), false);
\t\t\t
\t\t\tif (i == this.index)
\t\t\t{
\t\t\t\tif (Math.round(last.x - pt.x) == 0)
\t\t \t\t{
\t\t\t\t\tlast.x = point.x;
\t\t\t\t\tpt.x = point.x;
\t\t \t\t}
\t\t \t\t
\t\t\t\tif (Math.round(last.y - pt.y) == 0)
\t\t \t\t{
\t\t \t\t\tlast.y = point.y;
\t\t \t\t\tpt.y = point.y;
\t\t \t\t}
\t\t\t}

\t\t\tif (i < pts.length - 1)
\t\t\t{
\t\t\t\tresult.push(pt);
\t\t\t}

\t\t\tlast = pt;
\t\t}
\t\t
\t\t// Replaces single point that intersects with source or target
\t\tif (result.length == 1)
\t\t{
\t\t\tvar source = this.state.getVisibleTerminalState(true);
\t\t\tvar target = this.state.getVisibleTerminalState(false);
\t\t\tvar scale = this.state.view.getScale();
\t\t\tvar tr = this.state.view.getTranslate();
\t\t\t
\t\t\tvar x = result[0].x * scale + tr.x;
\t\t\tvar y = result[0].y * scale + tr.y;
\t\t\t
\t\t\tif ((source != null && mxUtils.contains(source, x, y)) ||
\t\t\t\t(target != null && mxUtils.contains(target, x, y)))
\t\t\t{
\t\t\t\tresult = [point, point];
\t\t\t}
\t\t}

\t\treturn result;
\t}
};

/**
 * Function: updatePreviewState
 * 
 * Overridden to perform optimization of the edge style result.
 */
mxEdgeSegmentHandler.prototype.updatePreviewState = function(edge, point, terminalState, me)
{
\tmxEdgeHandler.prototype.updatePreviewState.apply(this, arguments);

\t// Checks and corrects preview by running edge style again
\tif (!this.isSource && !this.isTarget)
\t{
\t\tpoint = this.convertPoint(point.clone(), false);
\t\tvar pts = edge.absolutePoints;
\t\tvar pt0 = pts[0];
\t\tvar pt1 = pts[1];

\t\tvar result = [];
\t\t
\t\tfor (var i = 2; i < pts.length; i++)
\t\t{
\t\t\tvar pt2 = pts[i];
\t\t
\t\t\t// Merges adjacent segments only if more than 2 to allow for straight edges
\t\t\tif ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
\t\t\t\t(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
\t\t\t{
\t\t\t\tresult.push(this.convertPoint(pt1.clone(), false));
\t\t\t}

\t\t\tpt0 = pt1;
\t\t\tpt1 = pt2;
\t\t}
\t\t
\t\tvar source = this.state.getVisibleTerminalState(true);
\t\tvar target = this.state.getVisibleTerminalState(false);
\t\tvar rpts = this.state.absolutePoints;
\t\t
\t\t// A straight line is represented by 3 handles
\t\tif (result.length == 0 && (Math.round(pts[0].x - pts[pts.length - 1].x) == 0 ||
\t\t\tMath.round(pts[0].y - pts[pts.length - 1].y) == 0))
\t\t{
\t\t\tresult = [point, point];
\t\t}
\t\t// Handles special case of transitions from straight vertical to routed
\t\telse if (pts.length == 5 && result.length == 2 && source != null && target != null &&
\t\t\t\trpts != null && Math.round(rpts[0].x - rpts[rpts.length - 1].x) == 0)
\t\t{
\t\t\tvar view = this.graph.getView();
\t\t\tvar scale = view.getScale();
\t\t\tvar tr = view.getTranslate();
\t\t\t
\t\t\tvar y0 = view.getRoutingCenterY(source) / scale - tr.y;
\t\t\t
\t\t\t// Use fixed connection point y-coordinate if one exists
\t\t\tvar sc = this.graph.getConnectionConstraint(edge, source, true);
\t\t\t
\t\t\tif (sc != null)
\t\t\t{
\t\t\t\tvar pt = this.graph.getConnectionPoint(source, sc);
\t\t\t\t
\t\t\t\tif (pt != null)
\t\t\t\t{
\t\t\t\t\tthis.convertPoint(pt, false);
\t\t\t\t\ty0 = pt.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tvar ye = view.getRoutingCenterY(target) / scale - tr.y;
\t\t\t
\t\t\t// Use fixed connection point y-coordinate if one exists
\t\t\tvar tc = this.graph.getConnectionConstraint(edge, target, false);
\t\t\t
\t\t\tif (tc)
\t\t\t{
\t\t\t\tvar pt = this.graph.getConnectionPoint(target, tc);
\t\t\t\t
\t\t\t\tif (pt != null)
\t\t\t\t{
\t\t\t\t\tthis.convertPoint(pt, false);
\t\t\t\t\tye = pt.y;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tresult = [new mxPoint(point.x, y0), new mxPoint(point.x, ye)];
\t\t}

\t\tthis.points = result;

\t\t// LATER: Check if points and result are different
\t\tedge.view.updateFixedTerminalPoints(edge, source, target);
\t\tedge.view.updatePoints(edge, this.points, source, target);
\t\tedge.view.updateFloatingTerminalPoints(edge, source, target);
\t}
};

/**
 * Overriden to merge edge segments.
 */
mxEdgeSegmentHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
{
\tvar model = this.graph.getModel();
\tvar geo = model.getGeometry(edge);
\tvar result = null;
\t
\t// Merges adjacent edge segments
\tif (geo != null && geo.points != null && geo.points.length > 0)
\t{
\t\tvar pts = this.abspoints;
\t\tvar pt0 = pts[0];
\t\tvar pt1 = pts[1];
\t\tresult = [];
\t\t
\t\tfor (var i = 2; i < pts.length; i++)
\t\t{
\t\t\tvar pt2 = pts[i];
\t\t
\t\t\t// Merges adjacent segments only if more than 2 to allow for straight edges
\t\t\tif ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
\t\t\t\t(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
\t\t\t{
\t\t\t\tresult.push(this.convertPoint(pt1.clone(), false));
\t\t\t}
\t
\t\t\tpt0 = pt1;
\t\t\tpt1 = pt2;
\t\t}
\t}
\t
\tmodel.beginUpdate();
\ttry
\t{
\t\tif (result != null)
\t\t{
\t\t\tvar geo = model.getGeometry(edge);
\t\t\t
\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tgeo = geo.clone();
\t\t\t\tgeo.points = result;
\t\t\t\t
\t\t\t\tmodel.setGeometry(edge, geo);
\t\t\t}
\t\t}
\t\t
\t\tedge = mxEdgeHandler.prototype.connect.apply(this, arguments);
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}
\t
\treturn edge;
};

/**
 * Function: getTooltipForNode
 * 
 * Returns no tooltips.
 */
mxEdgeSegmentHandler.prototype.getTooltipForNode = function(node)
{
\treturn null;
};

/**
 * Function: start
 * 
 * Starts the handling of the mouse gesture.
 */
mxEdgeSegmentHandler.prototype.start = function(x, y, index)
{
\tmxEdgeHandler.prototype.start.apply(this, arguments);
\t
\tif (this.bends != null && this.bends[index] != null &&
\t\t!this.isSource && !this.isTarget)
\t{
\t\tmxUtils.setOpacity(this.bends[index].node, 100);
\t}
};

/**
 * Function: createBends
 * 
 * Adds custom bends for the center of each segment.
 */
mxEdgeSegmentHandler.prototype.createBends = function()
{
\tvar bends = [];
\t
\t// Source
\tvar bend = this.createHandleShape(0);
\tthis.initBend(bend);
\tbend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
\tbends.push(bend);

\tvar pts = this.getCurrentPoints();

\t// Waypoints (segment handles)
\tif (this.graph.isCellBendable(this.state.cell))
\t{
\t\tif (this.points == null)
\t\t{
\t\t\tthis.points = [];
\t\t}

\t\tfor (var i = 0; i < pts.length - 1; i++)
\t\t{
\t\t\tbend = this.createVirtualBend();
\t\t\tbends.push(bend);
\t\t\tvar horizontal = Math.round(pts[i].x - pts[i + 1].x) == 0;
\t\t\t
\t\t\t// Special case where dy is 0 as well
\t\t\tif (Math.round(pts[i].y - pts[i + 1].y) == 0 && i < pts.length - 2)
\t\t\t{
\t\t\t\thorizontal = Math.round(pts[i].x - pts[i + 2].x) == 0;
\t\t\t}
\t\t\t
\t\t\tbend.setCursor((horizontal) ? 'col-resize' : 'row-resize');
\t\t\tthis.points.push(new mxPoint(0,0));
\t\t}
\t}

\t// Target
\tvar bend = this.createHandleShape(pts.length);
\tthis.initBend(bend);
\tbend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
\tbends.push(bend);

\treturn bends;
};

/**
 * Function: redraw
 * 
 * Overridden to invoke <refresh> before the redraw.
 */
mxEdgeSegmentHandler.prototype.redraw = function()
{
\tthis.refresh();
\tmxEdgeHandler.prototype.redraw.apply(this, arguments);
};

/**
 * Function: redrawInnerBends
 * 
 * Updates the position of the custom bends.
 */
mxEdgeSegmentHandler.prototype.redrawInnerBends = function(p0, pe)
{
\tif (this.graph.isCellBendable(this.state.cell))
\t{
\t\tvar pts = this.getCurrentPoints();
\t\t
\t\tif (pts != null && pts.length > 1)
\t\t{
\t\t\tvar straight = false;
\t\t\t
\t\t\t// Puts handle in the center of straight edges
\t\t\tif (pts.length == 4 && Math.round(pts[1].x - pts[2].x) == 0 && Math.round(pts[1].y - pts[2].y) == 0)
\t\t\t{
\t\t\t\tstraight = true;
\t\t\t\t
\t\t\t\tif (Math.round(pts[0].y - pts[pts.length - 1].y) == 0)
\t\t\t\t{
\t\t\t\t\tvar cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
\t\t\t\t\tpts[1] = new mxPoint(cx, pts[1].y);
\t\t\t\t\tpts[2] = new mxPoint(cx, pts[2].y);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
\t\t\t\t\tpts[1] = new mxPoint(pts[1].x, cy);
\t\t\t\t\tpts[2] = new mxPoint(pts[2].x, cy);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tfor (var i = 0; i < pts.length - 1; i++)
\t\t\t{
\t\t\t\tif (this.bends[i + 1] != null)
\t\t\t\t{
\t\t \t\t\tvar p0 = pts[i];
\t \t\t\t\tvar pe = pts[i + 1];
\t\t\t \t\tvar pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
\t\t\t \t\tvar b = this.bends[i + 1].bounds;
\t\t\t \t\tthis.bends[i + 1].bounds = new mxRectangle(Math.floor(pt.x - b.width / 2),
\t\t\t \t\t\t\tMath.floor(pt.y - b.height / 2), b.width, b.height);
\t\t\t\t \tthis.bends[i + 1].redraw();
\t\t\t\t \t
\t\t\t\t \tif (this.manageLabelHandle)
\t\t\t\t\t{
\t\t\t\t\t\tthis.checkLabelHandle(this.bends[i + 1].bounds);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (straight)
\t\t\t{
\t\t\t\tmxUtils.setOpacity(this.bends[1].node, this.virtualBendOpacity);
\t\t\t\tmxUtils.setOpacity(this.bends[3].node, this.virtualBendOpacity);
\t\t\t}
\t\t}
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxKeyHandler
 *
 * Event handler that listens to keystroke events. This is not a singleton,
 * however, it is normally only required once if the target is the document
 * element (default).
 * 
 * This handler installs a key event listener in the topmost DOM node and
 * processes all events that originate from descandants of <mxGraph.container>
 * or from the topmost DOM node. The latter means that all unhandled keystrokes
 * are handled by this object regardless of the focused state of the <graph>.
 * 
 * Example:
 * 
 * The following example creates a key handler that listens to the delete key
 * (46) and deletes the selection cells if the graph is enabled.
 * 
 * (code)
 * var keyHandler = new mxKeyHandler(graph);
 * keyHandler.bindKey(46, function(evt)
 * {
 *   if (graph.isEnabled())
 *   {
 *     graph.removeCells();
 *   }
 * });
 * (end)
 * 
 * Keycodes:
 * 
 * See http://tinyurl.com/yp8jgl or http://tinyurl.com/229yqw for a list of
 * keycodes or install a key event listener into the document element and print
 * the key codes of the respective events to the console.
 * 
 * To support the Command key and the Control key on the Mac, the following
 * code can be used.
 *
 * (code)
 * keyHandler.getFunction = function(evt)
 * {
 *   if (evt != null)
 *   {
 *     return (mxEvent.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey)) ? this.controlKeys[evt.keyCode] : this.normalKeys[evt.keyCode];
 *   }
 *   
 *   return null;
 * };
 * (end)
 * 
 * Constructor: mxKeyHandler
 *
 * Constructs an event handler that executes functions bound to specific
 * keystrokes.
 * 
 * Parameters:
 * 
 * graph - Reference to the associated <mxGraph>.
 * target - Optional reference to the event target. If null, the document
 * element is used as the event target, that is, the object where the key
 * event listener is installed.
 */
function mxKeyHandler(graph, target)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.target = target || document.documentElement;
\t\t
\t\t// Creates the arrays to map from keycodes to functions
\t\tthis.normalKeys = [];
\t\tthis.shiftKeys = [];
\t\tthis.controlKeys = [];
\t\tthis.controlShiftKeys = [];
\t\t
\t\tthis.keydownHandler = mxUtils.bind(this, function(evt)
\t\t{
\t\t\tthis.keyDown(evt);
\t\t});

\t\t// Installs the keystroke listener in the target
\t\tmxEvent.addListener(this.target, 'keydown', this.keydownHandler);
\t\t
\t\t// Automatically deallocates memory in IE
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\tmxEvent.addListener(window, 'unload',
\t\t\t\tmxUtils.bind(this, function()
\t\t\t\t{
\t\t\t\t\tthis.destroy();
\t\t\t\t})
\t\t\t);
\t\t}
\t}
};

/**
 * Variable: graph
 * 
 * Reference to the <mxGraph> associated with this handler.
 */
mxKeyHandler.prototype.graph = null;

/**
 * Variable: target
 * 
 * Reference to the target DOM, that is, the DOM node where the key event
 * listeners are installed.
 */
mxKeyHandler.prototype.target = null;

/**
 * Variable: normalKeys
 * 
 * Maps from keycodes to functions for non-pressed control keys.
 */
mxKeyHandler.prototype.normalKeys = null;

/**
 * Variable: shiftKeys
 * 
 * Maps from keycodes to functions for pressed shift keys.
 */
mxKeyHandler.prototype.shiftKeys = null;

/**
 * Variable: controlKeys
 * 
 * Maps from keycodes to functions for pressed control keys.
 */
mxKeyHandler.prototype.controlKeys = null;

/**
 * Variable: controlShiftKeys
 * 
 * Maps from keycodes to functions for pressed control and shift keys.
 */
mxKeyHandler.prototype.controlShiftKeys = null;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxKeyHandler.prototype.enabled = true;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation returns
 * <enabled>.
 */
mxKeyHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling by updating <enabled>.
 * 
 * Parameters:
 * 
 * enabled - Boolean that specifies the new enabled state.
 */
mxKeyHandler.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: bindKey
 * 
 * Binds the specified keycode to the given function. This binding is used
 * if the control key is not pressed.
 * 
 * Parameters:
 *
 * code - Integer that specifies the keycode.
 * funct - JavaScript function that takes the key event as an argument.
 */
mxKeyHandler.prototype.bindKey = function(code, funct)
{
\tthis.normalKeys[code] = funct;
};

/**
 * Function: bindShiftKey
 * 
 * Binds the specified keycode to the given function. This binding is used
 * if the shift key is pressed.
 * 
 * Parameters:
 *
 * code - Integer that specifies the keycode.
 * funct - JavaScript function that takes the key event as an argument.
 */
mxKeyHandler.prototype.bindShiftKey = function(code, funct)
{
\tthis.shiftKeys[code] = funct;
};

/**
 * Function: bindControlKey
 * 
 * Binds the specified keycode to the given function. This binding is used
 * if the control key is pressed.
 * 
 * Parameters:
 *
 * code - Integer that specifies the keycode.
 * funct - JavaScript function that takes the key event as an argument.
 */
mxKeyHandler.prototype.bindControlKey = function(code, funct)
{
\tthis.controlKeys[code] = funct;
};

/**
 * Function: bindControlShiftKey
 * 
 * Binds the specified keycode to the given function. This binding is used
 * if the control and shift key are pressed.
 * 
 * Parameters:
 *
 * code - Integer that specifies the keycode.
 * funct - JavaScript function that takes the key event as an argument.
 */
mxKeyHandler.prototype.bindControlShiftKey = function(code, funct)
{
\tthis.controlShiftKeys[code] = funct;
};

/**
 * Function: isControlDown
 * 
 * Returns true if the control key is pressed. This uses <mxEvent.isControlDown>.
 * 
 * Parameters:
 * 
 * evt - Key event whose control key pressed state should be returned.
 */
mxKeyHandler.prototype.isControlDown = function(evt)
{
\treturn mxEvent.isControlDown(evt);
};

/**
 * Function: getFunction
 * 
 * Returns the function associated with the given key event or null if no
 * function is associated with the given event.
 * 
 * Parameters:
 * 
 * evt - Key event whose associated function should be returned.
 */
mxKeyHandler.prototype.getFunction = function(evt)
{
\tif (evt != null && !mxEvent.isAltDown(evt))
\t{
\t\tif (this.isControlDown(evt))
\t\t{
\t\t\tif (mxEvent.isShiftDown(evt))
\t\t\t{
\t\t\t\treturn this.controlShiftKeys[evt.keyCode];
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn this.controlKeys[evt.keyCode];
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tif (mxEvent.isShiftDown(evt))
\t\t\t{
\t\t\t\treturn this.shiftKeys[evt.keyCode];
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\treturn this.normalKeys[evt.keyCode];
\t\t\t}
\t\t}
\t}
\t
\treturn null;
};
\t
/**
 * Function: isGraphEvent
 * 
 * Returns true if the event should be processed by this handler, that is,
 * if the event source is either the target, one of its direct children, a
 * descendant of the <mxGraph.container>, or the <mxGraph.cellEditor> of the
 * <graph>.
 * 
 * Parameters:
 * 
 * evt - Key event that represents the keystroke.
 */
mxKeyHandler.prototype.isGraphEvent = function(evt)
{
\tvar source = mxEvent.getSource(evt);
\t
\t// Accepts events from the target object or
\t// in-place editing inside graph
\tif ((source == this.target || source.parentNode == this.target) ||
\t\t(this.graph.cellEditor != null && this.graph.cellEditor.isEventSource(evt)))
\t{
\t\treturn true;
\t}
\t
\t// Accepts events from inside the container
\treturn mxUtils.isAncestorNode(this.graph.container, source);
};

/**
 * Function: keyDown
 * 
 * Handles the event by invoking the function bound to the respective keystroke
 * if <isEnabledForEvent> returns true for the given event and if
 * <isEventIgnored> returns false, except for escape for which
 * <isEventIgnored> is not invoked.
 * 
 * Parameters:
 * 
 * evt - Key event that represents the keystroke.
 */
mxKeyHandler.prototype.keyDown = function(evt)
{
\tif (this.isEnabledForEvent(evt))
\t{
\t\t// Cancels the editing if escape is pressed
\t\tif (evt.keyCode == 27 /* Escape */)
\t\t{
\t\t\tthis.escape(evt);
\t\t}
\t\t
\t\t// Invokes the function for the keystroke
\t\telse if (!this.isEventIgnored(evt))
\t\t{
\t\t\tvar boundFunction = this.getFunction(evt);
\t\t\t
\t\t\tif (boundFunction != null)
\t\t\t{
\t\t\t\tboundFunction(evt);
\t\t\t\tmxEvent.consume(evt);
\t\t\t}
\t\t}
\t}
};

/**
 * Function: isEnabledForEvent
 * 
 * Returns true if the given event should be handled. <isEventIgnored> is
 * called later if the event is not an escape key stroke, in which case
 * <escape> is called. This implementation returns true if <isEnabled>
 * returns true for both, this handler and <graph>, if the event is not
 * consumed and if <isGraphEvent> returns true.
 * 
 * Parameters:
 * 
 * evt - Key event that represents the keystroke.
 */
mxKeyHandler.prototype.isEnabledForEvent = function(evt)
{
\treturn (this.graph.isEnabled() && !mxEvent.isConsumed(evt) &&
\t\tthis.isGraphEvent(evt) && this.isEnabled());
};

/**
 * Function: isEventIgnored
 * 
 * Returns true if the given keystroke should be ignored. This returns
 * graph.isEditing().
 * 
 * Parameters:
 * 
 * evt - Key event that represents the keystroke.
 */
mxKeyHandler.prototype.isEventIgnored = function(evt)
{
\treturn this.graph.isEditing();
};

/**
 * Function: escape
 * 
 * Hook to process ESCAPE keystrokes. This implementation invokes
 * <mxGraph.stopEditing> to cancel the current editing, connecting
 * and/or other ongoing modifications.
 * 
 * Parameters:
 * 
 * evt - Key event that represents the keystroke. Possible keycode in this
 * case is 27 (ESCAPE).
 */
mxKeyHandler.prototype.escape = function(evt)
{
\tif (this.graph.isEscapeEnabled())
\t{
\t\tthis.graph.escape(evt);
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its references into the DOM. This does
 * normally not need to be called, it is called automatically when the
 * window unloads (in IE).
 */
mxKeyHandler.prototype.destroy = function()
{
\tif (this.target != null && this.keydownHandler != null)
\t{
\t\tmxEvent.removeListener(this.target, 'keydown', this.keydownHandler);
\t\tthis.keydownHandler = null;
\t}
\t
\tthis.target = null;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxTooltipHandler
 * 
 * Graph event handler that displays tooltips. <mxGraph.getTooltip> is used to
 * get the tooltip for a cell or handle. This handler is built-into
 * <mxGraph.tooltipHandler> and enabled using <mxGraph.setTooltips>.
 *
 * Example:
 * 
 * (code>
 * new mxTooltipHandler(graph);
 * (end)
 * 
 * Constructor: mxTooltipHandler
 * 
 * Constructs an event handler that displays tooltips with the specified
 * delay (in milliseconds). If no delay is specified then a default delay
 * of 500 ms (0.5 sec) is used.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * delay - Optional delay in milliseconds.
 */
function mxTooltipHandler(graph, delay)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.delay = delay || 500;
\t\tthis.graph.addMouseListener(this);
\t}
};

/**
 * Variable: zIndex
 * 
 * Specifies the zIndex for the tooltip and its shadow. Default is 10005.
 */
mxTooltipHandler.prototype.zIndex = 10005;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxTooltipHandler.prototype.graph = null;

/**
 * Variable: delay
 * 
 * Delay to show the tooltip in milliseconds. Default is 500.
 */
mxTooltipHandler.prototype.delay = null;

/**
 * Variable: ignoreTouchEvents
 * 
 * Specifies if touch and pen events should be ignored. Default is true.
 */
mxTooltipHandler.prototype.ignoreTouchEvents = true;

/**
 * Variable: hideOnHover
 * 
 * Specifies if the tooltip should be hidden if the mouse is moved over the
 * current cell. Default is false.
 */
mxTooltipHandler.prototype.hideOnHover = false;

/**
 * Variable: destroyed
 * 
 * True if this handler was destroyed using <destroy>.
 */
mxTooltipHandler.prototype.destroyed = false;

/**
 * Variable: enabled
 * 
 * Specifies if events are handled. Default is true.
 */
mxTooltipHandler.prototype.enabled = true;

/**
 * Function: isEnabled
 * 
 * Returns true if events are handled. This implementation
 * returns <enabled>.
 */
mxTooltipHandler.prototype.isEnabled = function()
{
\treturn this.enabled;
};

/**
 * Function: setEnabled
 * 
 * Enables or disables event handling. This implementation
 * updates <enabled>.
 */
mxTooltipHandler.prototype.setEnabled = function(enabled)
{
\tthis.enabled = enabled;
};

/**
 * Function: isHideOnHover
 * 
 * Returns <hideOnHover>.
 */
mxTooltipHandler.prototype.isHideOnHover = function()
{
\treturn this.hideOnHover;
};

/**
 * Function: setHideOnHover
 * 
 * Sets <hideOnHover>.
 */
mxTooltipHandler.prototype.setHideOnHover = function(value)
{
\tthis.hideOnHover = value;
};

/**
 * Function: init
 * 
 * Initializes the DOM nodes required for this tooltip handler.
 */
mxTooltipHandler.prototype.init = function()
{
\tif (document.body != null)
\t{
\t\tthis.div = document.createElement('div');
\t\tthis.div.className = 'mxTooltip';
\t\tthis.div.style.visibility = 'hidden';

\t\tdocument.body.appendChild(this.div);

\t\tmxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
\t\t{
\t\t\tvar source = mxEvent.getSource(evt);
\t\t\t
\t\t\tif (source.nodeName != 'A')
\t\t\t{
\t\t\t\tthis.hideTooltip();
\t\t\t}
\t\t}));
\t}
};

/**
 * Function: getStateForEvent
 * 
 * Returns the <mxCellState> to be used for showing a tooltip for this event.
 */
mxTooltipHandler.prototype.getStateForEvent = function(me)
{
\treturn me.getState();
};

/**
 * Function: mouseDown
 * 
 * Handles the event by initiating a rubberband selection. By consuming the
 * event all subsequent events of the gesture are redirected to this
 * handler.
 */
mxTooltipHandler.prototype.mouseDown = function(sender, me)
{
\tthis.reset(me, false);
\tthis.hideTooltip();
};

/**
 * Function: mouseMove
 * 
 * Handles the event by updating the rubberband selection.
 */
mxTooltipHandler.prototype.mouseMove = function(sender, me)
{
\tif (me.getX() != this.lastX || me.getY() != this.lastY)
\t{
\t\tthis.reset(me, true);
\t\tvar state = this.getStateForEvent(me);
\t\t
\t\tif (this.isHideOnHover() || state != this.state || (me.getSource() != this.node &&
\t\t\t(!this.stateSource || (state != null && this.stateSource ==
\t\t\t(me.isSource(state.shape) || !me.isSource(state.text))))))
\t\t{
\t\t\tthis.hideTooltip();
\t\t}
\t}
\t
\tthis.lastX = me.getX();
\tthis.lastY = me.getY();
};

/**
 * Function: mouseUp
 * 
 * Handles the event by resetting the tooltip timer or hiding the existing
 * tooltip.
 */
mxTooltipHandler.prototype.mouseUp = function(sender, me)
{
\tthis.reset(me, true);
\tthis.hideTooltip();
};


/**
 * Function: resetTimer
 * 
 * Resets the timer.
 */
mxTooltipHandler.prototype.resetTimer = function()
{
\tif (this.thread != null)
\t{
\t\twindow.clearTimeout(this.thread);
\t\tthis.thread = null;
\t}
};

/**
 * Function: reset
 * 
 * Resets and/or restarts the timer to trigger the display of the tooltip.
 */
mxTooltipHandler.prototype.reset = function(me, restart, state)
{
\tif (!this.ignoreTouchEvents || mxEvent.isMouseEvent(me.getEvent()))
\t{
\t\tthis.resetTimer();
\t\tstate = (state != null) ? state : this.getStateForEvent(me);
\t\t
\t\tif (restart && this.isEnabled() && state != null && (this.div == null ||
\t\t\tthis.div.style.visibility == 'hidden'))
\t\t{
\t\t\tvar node = me.getSource();
\t\t\tvar x = me.getX();
\t\t\tvar y = me.getY();
\t\t\tvar stateSource = me.isSource(state.shape) || me.isSource(state.text);
\t
\t\t\tthis.thread = window.setTimeout(mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tif (!this.graph.isEditing() && !this.graph.popupMenuHandler.isMenuShowing() && !this.graph.isMouseDown)
\t\t\t\t{
\t\t\t\t\t// Uses information from inside event cause using the event at
\t\t\t\t\t// this (delayed) point in time is not possible in IE as it no
\t\t\t\t\t// longer contains the required information (member not found)
\t\t\t\t\tvar tip = this.graph.getTooltip(state, node, x, y);
\t\t\t\t\tthis.show(tip, x, y);
\t\t\t\t\tthis.state = state;
\t\t\t\t\tthis.node = node;
\t\t\t\t\tthis.stateSource = stateSource;
\t\t\t\t}
\t\t\t}), this.delay);
\t\t}
\t}
};

/**
 * Function: hide
 * 
 * Hides the tooltip and resets the timer.
 */
mxTooltipHandler.prototype.hide = function()
{
\tthis.resetTimer();
\tthis.hideTooltip();
};

/**
 * Function: hideTooltip
 * 
 * Hides the tooltip.
 */
mxTooltipHandler.prototype.hideTooltip = function()
{
\tif (this.div != null)
\t{
\t\tthis.div.style.visibility = 'hidden';
\t\tthis.div.innerHTML = '';
\t}
};

/**
 * Function: show
 * 
 * Shows the tooltip for the specified cell and optional index at the
 * specified location (with a vertical offset of 10 pixels).
 */
mxTooltipHandler.prototype.show = function(tip, x, y)
{
\tif (!this.destroyed && tip != null && tip.length > 0)
\t{
\t\t// Initializes the DOM nodes if required
\t\tif (this.div == null)
\t\t{
\t\t\tthis.init();
\t\t}
\t\t
\t\tvar origin = mxUtils.getScrollOrigin();

\t\tthis.div.style.zIndex = this.zIndex;
\t\tthis.div.style.left = (x + origin.x) + 'px';
\t\tthis.div.style.top = (y + mxConstants.TOOLTIP_VERTICAL_OFFSET +
\t\t\torigin.y) + 'px';

\t\tif (!mxUtils.isNode(tip))
\t\t{\t
\t\t\tthis.div.innerHTML = tip.replace(/\\n/g, '<br>');
\t\t}
\t\telse
\t\t{
\t\t\tthis.div.innerHTML = '';
\t\t\tthis.div.appendChild(tip);
\t\t}
\t\t
\t\tthis.div.style.visibility = '';
\t\tmxUtils.fit(this.div);
\t}
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxTooltipHandler.prototype.destroy = function()
{
\tif (!this.destroyed)
\t{
\t\tthis.graph.removeMouseListener(this);
\t\tmxEvent.release(this.div);
\t\t
\t\tif (this.div != null && this.div.parentNode != null)
\t\t{
\t\t\tthis.div.parentNode.removeChild(this.div);
\t\t}
\t\t
\t\tthis.destroyed = true;
\t\tthis.div = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellTracker
 * 
 * Event handler that highlights cells. Inherits from <mxCellMarker>.
 * 
 * Example:
 * 
 * (code)
 * new mxCellTracker(graph, '#00FF00');
 * (end)
 * 
 * For detecting dragEnter, dragOver and dragLeave on cells, the following
 * code can be used:
 * 
 * (code)
 * graph.addMouseListener(
 * {
 *   cell: null,
 *   mouseDown: function(sender, me) { },
 *   mouseMove: function(sender, me)
 *   {
 *     var tmp = me.getCell();
 *     
 *     if (tmp != this.cell)
 *     {
 *       if (this.cell != null)
 *       {
 *         this.dragLeave(me.getEvent(), this.cell);
 *       }
 *       
 *       this.cell = tmp;
 *       
 *       if (this.cell != null)
 *       {
 *         this.dragEnter(me.getEvent(), this.cell);
 *       }
 *     }
 *     
 *     if (this.cell != null)
 *     {
 *       this.dragOver(me.getEvent(), this.cell);
 *     }
 *   },
 *   mouseUp: function(sender, me) { },
 *   dragEnter: function(evt, cell)
 *   {
 *     mxLog.debug('dragEnter', cell.value);
 *   },
 *   dragOver: function(evt, cell)
 *   {
 *     mxLog.debug('dragOver', cell.value);
 *   },
 *   dragLeave: function(evt, cell)
 *   {
 *     mxLog.debug('dragLeave', cell.value);
 *   }
 * });
 * (end)
 * 
 * Constructor: mxCellTracker
 * 
 * Constructs an event handler that highlights cells.
 * 
 * Parameters:
 * 
 * graph - Reference to the enclosing <mxGraph>.
 * color - Color of the highlight. Default is blue.
 * funct - Optional JavaScript function that is used to override
 * <mxCellMarker.getCell>.
 */
function mxCellTracker(graph, color, funct)
{
\tmxCellMarker.call(this, graph, color);

\tthis.graph.addMouseListener(this);
\t
\tif (funct != null)
\t{
\t\tthis.getCell = funct;
\t}
\t
\t// Automatic deallocation of memory
\tif (mxClient.IS_IE)
\t{
\t\tmxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
\t\t{
\t\t\tthis.destroy();
\t\t}));
\t}
};

/**
 * Extends mxCellMarker.
 */
mxUtils.extend(mxCellTracker, mxCellMarker);

/**
 * Function: mouseDown
 * 
 * Ignores the event. The event is not consumed.
 */
mxCellTracker.prototype.mouseDown = function(sender, me) { };

/**
 * Function: mouseMove
 * 
 * Handles the event by highlighting the cell under the mousepointer if it
 * is over the hotspot region of the cell.
 */
mxCellTracker.prototype.mouseMove = function(sender, me)
{
\tif (this.isEnabled())
\t{
\t\tthis.process(me);
\t}
};

/**
 * Function: mouseUp
 * 
 * Handles the event by reseting the highlight.
 */
mxCellTracker.prototype.mouseUp = function(sender, me) { };

/**
 * Function: destroy
 * 
 * Destroys the object and all its resources and DOM nodes. This doesn't
 * normally need to be called. It is called automatically when the window
 * unloads.
 */
mxCellTracker.prototype.destroy = function()
{
\tif (!this.destroyed)
\t{
\t\tthis.destroyed = true;

\t\tthis.graph.removeMouseListener(this);
\t\tmxCellMarker.prototype.destroy.apply(this);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCellHighlight
 * 
 * A helper class to highlight cells. Here is an example for a given cell.
 * 
 * (code)
 * var highlight = new mxCellHighlight(graph, '#ff0000', 2);
 * highlight.highlight(graph.view.getState(cell)));
 * (end)
 * 
 * Constructor: mxCellHighlight
 * 
 * Constructs a cell highlight.
 */
function mxCellHighlight(graph, highlightColor, strokeWidth, dashed)
{
\tif (graph != null)
\t{
\t\tthis.graph = graph;
\t\tthis.highlightColor = (highlightColor != null) ? highlightColor : mxConstants.DEFAULT_VALID_COLOR;
\t\tthis.strokeWidth = (strokeWidth != null) ? strokeWidth : mxConstants.HIGHLIGHT_STROKEWIDTH;
\t\tthis.dashed = (dashed != null) ? dashed : false;
\t\tthis.opacity = mxConstants.HIGHLIGHT_OPACITY;

\t\t// Updates the marker if the graph changes
\t\tthis.repaintHandler = mxUtils.bind(this, function()
\t\t{
\t\t\t// Updates reference to state
\t\t\tif (this.state != null)
\t\t\t{
\t\t\t\tvar tmp = this.graph.view.getState(this.state.cell);
\t\t\t\t
\t\t\t\tif (tmp == null)
\t\t\t\t{
\t\t\t\t\tthis.hide();
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tthis.state = tmp;
\t\t\t\t\tthis.repaint();
\t\t\t\t}
\t\t\t}
\t\t});

\t\tthis.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler);
\t\tthis.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler);
\t\tthis.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler);
\t\tthis.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler);
\t\t
\t\t// Hides the marker if the current root changes
\t\tthis.resetHandler = mxUtils.bind(this, function()
\t\t{
\t\t\tthis.hide();
\t\t});

\t\tthis.graph.getView().addListener(mxEvent.DOWN, this.resetHandler);
\t\tthis.graph.getView().addListener(mxEvent.UP, this.resetHandler);
\t}
};

/**
 * Variable: keepOnTop
 * 
 * Specifies if the highlights should appear on top of everything
 * else in the overlay pane. Default is false.
 */
mxCellHighlight.prototype.keepOnTop = false;

/**
 * Variable: graph
 * 
 * Reference to the enclosing <mxGraph>.
 */
mxCellHighlight.prototype.graph = null;

/**
 * Variable: state
 * 
 * Reference to the <mxCellState>.
 */
mxCellHighlight.prototype.state = null;

/**
 * Variable: spacing
 * 
 * Specifies the spacing between the highlight for vertices and the vertex.
 * Default is 2.
 */
mxCellHighlight.prototype.spacing = 2;

/**
 * Variable: resetHandler
 * 
 * Holds the handler that automatically invokes reset if the highlight
 * should be hidden.
 */
mxCellHighlight.prototype.resetHandler = null;

/**
 * Function: setHighlightColor
 * 
 * Sets the color of the rectangle used to highlight drop targets.
 * 
 * Parameters:
 * 
 * color - String that represents the new highlight color.
 */
mxCellHighlight.prototype.setHighlightColor = function(color)
{
\tthis.highlightColor = color;
\t
\tif (this.shape != null)
\t{
\t\tthis.shape.stroke = color;
\t}
};

/**
 * Function: drawHighlight
 * 
 * Creates and returns the highlight shape for the given state.
 */
mxCellHighlight.prototype.drawHighlight = function()
{
\tthis.shape = this.createShape();
\tthis.repaint();

\tif (!this.keepOnTop && this.shape.node.parentNode.firstChild != this.shape.node)
\t{
\t\tthis.shape.node.parentNode.insertBefore(this.shape.node, this.shape.node.parentNode.firstChild);
\t}
};

/**
 * Function: createShape
 * 
 * Creates and returns the highlight shape for the given state.
 */
mxCellHighlight.prototype.createShape = function()
{
\tvar shape = this.graph.cellRenderer.createShape(this.state);
\t
\tshape.svgStrokeTolerance = this.graph.tolerance;
\tshape.points = this.state.absolutePoints;
\tshape.apply(this.state);
\tshape.stroke = this.highlightColor;
\tshape.opacity = this.opacity;
\tshape.isDashed = this.dashed;
\tshape.isShadow = false;
\t
\tshape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
\tshape.init(this.graph.getView().getOverlayPane());
\tmxEvent.redirectMouseEvents(shape.node, this.graph, this.state);
\t
\tif (this.graph.dialect != mxConstants.DIALECT_SVG)
\t{
\t\tshape.pointerEvents = false;
\t}
\telse
\t{
\t\tshape.svgPointerEvents = 'stroke';
\t}
\t
\treturn shape;
};

/**
 * Function: getStrokeWidth
 * 
 * Returns the stroke width.
 */
mxCellHighlight.prototype.getStrokeWidth = function(state)
{
\treturn this.strokeWidth;
};

/**
 * Function: repaint
 * 
 * Updates the highlight after a change of the model or view.
 */
mxCellHighlight.prototype.repaint = function()
{
\tif (this.state != null && this.shape != null)
\t{
\t\tthis.shape.scale = this.state.view.scale;
\t\t
\t\tif (this.graph.model.isEdge(this.state.cell))
\t\t{
\t\t\tthis.shape.strokewidth = this.getStrokeWidth();
\t\t\tthis.shape.points = this.state.absolutePoints;
\t\t\tthis.shape.outline = false;
\t\t}
\t\telse
\t\t{
\t\t\tthis.shape.bounds = new mxRectangle(this.state.x - this.spacing, this.state.y - this.spacing,
\t\t\t\t\tthis.state.width + 2 * this.spacing, this.state.height + 2 * this.spacing);
\t\t\tthis.shape.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
\t\t\tthis.shape.strokewidth = this.getStrokeWidth() / this.state.view.scale;
\t\t\tthis.shape.outline = true;
\t\t}

\t\t// Uses cursor from shape in highlight
\t\tif (this.state.shape != null)
\t\t{
\t\t\tthis.shape.setCursor(this.state.shape.getCursor());
\t\t}
\t\t
\t\t// Workaround for event transparency in VML with transparent color
\t\t// is to use a non-transparent color with near zero opacity
\t\tif (mxClient.IS_QUIRKS || document.documentMode == 8)
\t\t{
\t\t\tif (this.shape.stroke == 'transparent')
\t\t\t{
\t\t\t\t// KNOWN: Quirks mode does not seem to catch events if
\t\t\t\t// we do not force an update of the DOM via a change such
\t\t\t\t// as mxLog.debug. Since IE6 is EOL we do not add a fix.
\t\t\t\tthis.shape.stroke = 'white';
\t\t\t\tthis.shape.opacity = 1;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.shape.opacity = this.opacity;
\t\t\t}
\t\t}
\t\t
\t\tthis.shape.redraw();
\t}
};

/**
 * Function: hide
 * 
 * Resets the state of the cell marker.
 */
mxCellHighlight.prototype.hide = function()
{
\tthis.highlight(null);
};

/**
 * Function: mark
 * 
 * Marks the <markedState> and fires a <mark> event.
 */
mxCellHighlight.prototype.highlight = function(state)
{
\tif (this.state != state)
\t{
\t\tif (this.shape != null)
\t\t{
\t\t\tthis.shape.destroy();
\t\t\tthis.shape = null;
\t\t}

\t\tthis.state = state;
\t\t
\t\tif (this.state != null)
\t\t{
\t\t\tthis.drawHighlight();
\t\t}
\t}
};

/**
 * Function: isHighlightAt
 * 
 * Returns true if this highlight is at the given position.
 */
mxCellHighlight.prototype.isHighlightAt = function(x, y)
{
\tvar hit = false;
\t
\t// Quirks mode is currently not supported as it used a different coordinate system
\tif (this.shape != null && document.elementFromPoint != null && !mxClient.IS_QUIRKS)
\t{
\t\tvar elt = document.elementFromPoint(x, y);

\t\twhile (elt != null)
\t\t{
\t\t\tif (elt == this.shape.node)
\t\t\t{
\t\t\t\thit = true;
\t\t\t\tbreak;
\t\t\t}
\t\t\t
\t\t\telt = elt.parentNode;
\t\t}
\t}
\t
\treturn hit;
};

/**
 * Function: destroy
 * 
 * Destroys the handler and all its resources and DOM nodes.
 */
mxCellHighlight.prototype.destroy = function()
{
\tthis.graph.getView().removeListener(this.resetHandler);
\tthis.graph.getView().removeListener(this.repaintHandler);
\tthis.graph.getModel().removeListener(this.repaintHandler);
\t
\tif (this.shape != null)
\t{
\t\tthis.shape.destroy();
\t\tthis.shape = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDefaultKeyHandler
 *
 * Binds keycodes to actionnames in an editor. This aggregates an internal
 * <handler> and extends the implementation of <mxKeyHandler.escape> to not
 * only cancel the editing, but also hide the properties dialog and fire an
 * <mxEditor.escape> event via <editor>. An instance of this class is created
 * by <mxEditor> and stored in <mxEditor.keyHandler>.
 * 
 * Example:
 * 
 * Bind the delete key to the delete action in an existing editor.
 * 
 * (code)
 * var keyHandler = new mxDefaultKeyHandler(editor);
 * keyHandler.bindAction(46, 'delete');
 * (end)
 *
 * Codec:
 * 
 * This class uses the <mxDefaultKeyHandlerCodec> to read configuration
 * data into an existing instance. See <mxDefaultKeyHandlerCodec> for a
 * description of the configuration format.
 * 
 * Keycodes:
 * 
 * See <mxKeyHandler>.
 * 
 * An <mxEvent.ESCAPE> event is fired via the editor if the escape key is
 * pressed.
 * 
 * Constructor: mxDefaultKeyHandler
 *
 * Constructs a new default key handler for the <mxEditor.graph> in the
 * given <mxEditor>. (The editor may be null if a prototypical instance for
 * a <mxDefaultKeyHandlerCodec> is created.)
 * 
 * Parameters:
 * 
 * editor - Reference to the enclosing <mxEditor>.
 */
function mxDefaultKeyHandler(editor)
{
\tif (editor != null)
\t{
\t\tthis.editor = editor;
\t\tthis.handler = new mxKeyHandler(editor.graph);
\t\t
\t\t// Extends the escape function of the internal key
\t\t// handle to hide the properties dialog and fire
\t\t// the escape event via the editor instance
\t\tvar old = this.handler.escape;
\t\t
\t\tthis.handler.escape = function(evt)
\t\t{
\t\t\told.apply(this, arguments);
\t\t\teditor.hideProperties();
\t\t\teditor.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt));
\t\t};
\t}
};
\t
/**
 * Variable: editor
 *
 * Reference to the enclosing <mxEditor>.
 */
mxDefaultKeyHandler.prototype.editor = null;

/**
 * Variable: handler
 *
 * Holds the <mxKeyHandler> for key event handling.
 */
mxDefaultKeyHandler.prototype.handler = null;

/**
 * Function: bindAction
 *
 * Binds the specified keycode to the given action in <editor>. The
 * optional control flag specifies if the control key must be pressed
 * to trigger the action.
 *
 * Parameters:
 *
 * code - Integer that specifies the keycode.
 * action - Name of the action to execute in <editor>.
 * control - Optional boolean that specifies if control must be pressed.
 * Default is false.
 */
mxDefaultKeyHandler.prototype.bindAction = function (code, action, control)
{
\tvar keyHandler = mxUtils.bind(this, function()
\t{
\t\tthis.editor.execute(action);
\t});

\t// Binds the function to control-down keycode
\tif (control)
\t{
\t\tthis.handler.bindControlKey(code, keyHandler);
\t}

\t// Binds the function to the normal keycode
\telse
\t{
\t\tthis.handler.bindKey(code, keyHandler);\t\t\t\t
\t}
};

/**
 * Function: destroy
 *
 * Destroys the <handler> associated with this object. This does normally
 * not need to be called, the <handler> is destroyed automatically when the
 * window unloads (in IE) by <mxEditor>.
 */
mxDefaultKeyHandler.prototype.destroy = function ()
{
\tthis.handler.destroy();
\tthis.handler = null;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDefaultPopupMenu
 *
 * Creates popupmenus for mouse events. This object holds an XML node
 * which is a description of the popup menu to be created. In
 * <createMenu>, the configuration is applied to the context and
 * the resulting menu items are added to the menu dynamically. See
 * <createMenu> for a description of the configuration format.
 * 
 * This class does not create the DOM nodes required for the popup menu, it
 * only parses an XML description to invoke the respective methods on an
 * <mxPopupMenu> each time the menu is displayed.
 *
 * Codec:
 * 
 * This class uses the <mxDefaultPopupMenuCodec> to read configuration
 * data into an existing instance, however, the actual parsing is done
 * by this class during program execution, so the format is described
 * below.
 * 
 * Constructor: mxDefaultPopupMenu
 *
 * Constructs a new popupmenu-factory based on given configuration.
 *
 * Paramaters:
 *
 * config - XML node that contains the configuration data.
 */
function mxDefaultPopupMenu(config)
{
\tthis.config = config;
};

/**
 * Variable: imageBasePath
 *
 * Base path for all icon attributes in the config. Default is null.
 */
mxDefaultPopupMenu.prototype.imageBasePath = null;

/**
 * Variable: config
 *
 * XML node used as the description of new menu items. This node is
 * used in <createMenu> to dynamically create the menu items if their
 * respective conditions evaluate to true for the given arguments.
 */
mxDefaultPopupMenu.prototype.config = null;

/**
 * Function: createMenu
 *
 * This function is called from <mxEditor> to add items to the
 * given menu based on <config>. The config is a sequence of
 * the following nodes and attributes.
 *
 * Child Nodes: 
 *
 * add - Adds a new menu item. See below for attributes.
 * separator - Adds a separator. No attributes.
 * condition - Adds a custom condition. Name attribute.
 * 
 * The add-node may have a child node that defines a function to be invoked
 * before the action is executed (or instead of an action to be executed).
 *
 * Attributes:
 *
 * as - Resource key for the label (needs entry in property file).
 * action - Name of the action to execute in enclosing editor.
 * icon - Optional icon (relative/absolute URL).
 * iconCls - Optional CSS class for the icon.
 * if - Optional name of condition that must be true (see below).
 * enabled-if - Optional name of condition that specifies if the menu item
 * should be enabled.
 * name - Name of custom condition. Only for condition nodes.
 *
 * Conditions:
 *
 * nocell - No cell under the mouse.
 * ncells - More than one cell selected.
 * notRoot - Drilling position is other than home.
 * cell - Cell under the mouse.
 * notEmpty - Exactly one cell with children under mouse.
 * expandable - Exactly one expandable cell under mouse.
 * collapsable - Exactly one collapsable cell under mouse.
 * validRoot - Exactly one cell which is a possible root under mouse.
 * swimlane - Exactly one cell which is a swimlane under mouse.
 *
 * Example:
 *
 * To add a new item for a given action to the popupmenu:
 * 
 * (code)
 * <mxDefaultPopupMenu as=\"popupHandler\">
 *   <add as=\"delete\" action=\"delete\" icon=\"images/delete.gif\" if=\"cell\"/>
 * </mxDefaultPopupMenu>
 * (end)
 * 
 * To add a new item for a custom function:
 * 
 * (code)
 * <mxDefaultPopupMenu as=\"popupHandler\">
 *   <add as=\"action1\"><![CDATA[
 *\t\tfunction (editor, cell, evt)
 *\t\t{
 *\t\t\teditor.execute('action1', cell, 'myArg');
 *\t\t}
 *   ]]></add>
 * </mxDefaultPopupMenu>
 * (end)
 * 
 * The above example invokes action1 with an additional third argument via
 * the editor instance. The third argument is passed to the function that
 * defines action1. If the add-node has no action-attribute, then only the
 * function defined in the text content is executed, otherwise first the
 * function and then the action defined in the action-attribute is
 * executed. The function in the text content has 3 arguments, namely the
 * <mxEditor> instance, the <mxCell> instance under the mouse, and the
 * native mouse event.
 *
 * Custom Conditions:
 *
 * To add a new condition for popupmenu items:
 *  
 * (code)
 * <condition name=\"condition1\"><![CDATA[
 *   function (editor, cell, evt)
 *   {
 *     return cell != null;
 *   }
 * ]]></condition>
 * (end)
 * 
 * The new condition can then be used in any item as follows:
 * 
 * (code)
 * <add as=\"action1\" action=\"action1\" icon=\"action1.gif\" if=\"condition1\"/>
 * (end)
 * 
 * The order in which the items and conditions appear is not significant as
 * all connditions are evaluated before any items are created.
 * 
 * Parameters:
 *
 * editor - Enclosing <mxEditor> instance.
 * menu - <mxPopupMenu> that is used for adding items and separators.
 * cell - Optional <mxCell> which is under the mousepointer.
 * evt - Optional mouse event which triggered the menu. 
 */
mxDefaultPopupMenu.prototype.createMenu = function(editor, menu, cell, evt)
{
\tif (this.config != null)
\t{
\t\tvar conditions = this.createConditions(editor, cell, evt);
\t\tvar item = this.config.firstChild;

\t\tthis.addItems(editor, menu, cell, evt, conditions, item, null);
\t}
};

/**
 * Function: addItems
 * 
 * Recursively adds the given items and all of its children into the given menu.
 * 
 * Parameters:
 *
 * editor - Enclosing <mxEditor> instance.
 * menu - <mxPopupMenu> that is used for adding items and separators.
 * cell - Optional <mxCell> which is under the mousepointer.
 * evt - Optional mouse event which triggered the menu.
 * conditions - Array of names boolean conditions.
 * item - XML node that represents the current menu item.
 * parent - DOM node that represents the parent menu item.
 */
mxDefaultPopupMenu.prototype.addItems = function(editor, menu, cell, evt, conditions, item, parent)
{
\tvar addSeparator = false;
\t
\twhile (item != null)
\t{
\t\tif (item.nodeName == 'add')
\t\t{
\t\t\tvar condition = item.getAttribute('if');
\t\t\t
\t\t\tif (condition == null || conditions[condition])
\t\t\t{
\t\t\t\tvar as = item.getAttribute('as');
\t\t\t\tas = mxResources.get(as) || as;
\t\t\t\tvar funct = mxUtils.eval(mxUtils.getTextContent(item));
\t\t\t\tvar action = item.getAttribute('action');
\t\t\t\tvar icon = item.getAttribute('icon');
\t\t\t\tvar iconCls = item.getAttribute('iconCls');
\t\t\t\tvar enabledCond = item.getAttribute('enabled-if');
\t\t\t\tvar enabled = enabledCond == null || conditions[enabledCond];
\t\t\t\t
\t\t\t\tif (addSeparator)
\t\t\t\t{
\t\t\t\t\tmenu.addSeparator(parent);
\t\t\t\t\taddSeparator = false;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (icon != null && this.imageBasePath)
\t\t\t\t{
\t\t\t\t\ticon = this.imageBasePath + icon;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar row = this.addAction(menu, editor, as, icon, funct, action, cell, parent, iconCls, enabled);
\t\t\t\tthis.addItems(editor, menu, cell, evt, conditions, item.firstChild, row);
\t\t\t}
\t\t}
\t\telse if (item.nodeName == 'separator')
\t\t{
\t\t\taddSeparator = true;
\t\t}
\t\t
\t\titem = item.nextSibling;
\t}
};

/**
 * Function: addAction
 *
 * Helper method to bind an action to a new menu item.
 * 
 * Parameters:
 *
 * menu - <mxPopupMenu> that is used for adding items and separators.
 * editor - Enclosing <mxEditor> instance.
 * lab - String that represents the label of the menu item.
 * icon - Optional URL that represents the icon of the menu item.
 * action - Optional name of the action to execute in the given editor.
 * funct - Optional function to execute before the optional action. The
 * function takes an <mxEditor>, the <mxCell> under the mouse and the
 * mouse event that triggered the call.
 * cell - Optional <mxCell> to use as an argument for the action.
 * parent - DOM node that represents the parent menu item.
 * iconCls - Optional CSS class for the menu icon.
 * enabled - Optional boolean that specifies if the menu item is enabled.
 * Default is true.
 */
mxDefaultPopupMenu.prototype.addAction = function(menu, editor, lab, icon, funct, action, cell, parent, iconCls, enabled)
{
\tvar clickHandler = function(evt)
\t{
\t\tif (typeof(funct) == 'function')
\t\t{
\t\t\tfunct.call(editor, editor, cell, evt);
\t\t}
\t\t
\t\tif (action != null)
\t\t{
\t\t\teditor.execute(action, cell, evt);
\t\t}
\t};
\t
\treturn menu.addItem(lab, icon, clickHandler, parent, iconCls, enabled);
};

/**
 * Function: createConditions
 * 
 * Evaluates the default conditions for the given context.
 */
mxDefaultPopupMenu.prototype.createConditions = function(editor, cell, evt)
{
\t// Creates array with conditions
\tvar model = editor.graph.getModel();
\tvar childCount = model.getChildCount(cell);
\t
\t// Adds some frequently used conditions
\tvar conditions = [];
\tconditions['nocell'] = cell == null;
\tconditions['ncells'] = editor.graph.getSelectionCount() > 1;
\tconditions['notRoot'] = model.getRoot() !=
\t\tmodel.getParent(editor.graph.getDefaultParent());
\tconditions['cell'] = cell != null;
\t
\tvar isCell = cell != null && editor.graph.getSelectionCount() == 1;
\tconditions['nonEmpty'] = isCell && childCount > 0;
\tconditions['expandable'] = isCell && editor.graph.isCellFoldable(cell, false);
\tconditions['collapsable'] = isCell && editor.graph.isCellFoldable(cell, true);
\tconditions['validRoot'] = isCell && editor.graph.isValidRoot(cell);
\tconditions['emptyValidRoot'] = conditions['validRoot'] && childCount == 0;
\tconditions['swimlane'] = isCell && editor.graph.isSwimlane(cell);

\t// Evaluates dynamic conditions from config file
\tvar condNodes = this.config.getElementsByTagName('condition');
\t
\tfor (var i=0; i<condNodes.length; i++)
\t{
\t\tvar funct = mxUtils.eval(mxUtils.getTextContent(condNodes[i]));
\t\tvar name = condNodes[i].getAttribute('name');
\t\t
\t\tif (name != null && typeof(funct) == 'function')
\t\t{
\t\t\tconditions[name] = funct(editor, cell, evt);
\t\t}
\t}
\t
\treturn conditions;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDefaultToolbar
 *
 * Toolbar for the editor. This modifies the state of the graph
 * or inserts new cells upon mouse clicks.
 * 
 * Example:
 * 
 * Create a toolbar with a button to copy the selection into the clipboard,
 * and a combo box with one action to paste the selection from the clipboard
 * into the graph.
 * 
 * (code)
 * var toolbar = new mxDefaultToolbar(container, editor);
 * toolbar.addItem('Copy', null, 'copy');
 * 
 * var combo = toolbar.addActionCombo('More actions...');
 * toolbar.addActionOption(combo, 'Paste', 'paste');
 * (end) 
 *
 * Codec:
 * 
 * This class uses the <mxDefaultToolbarCodec> to read configuration
 * data into an existing instance. See <mxDefaultToolbarCodec> for a
 * description of the configuration format.
 * 
 * Constructor: mxDefaultToolbar
 *
 * Constructs a new toolbar for the given container and editor. The
 * container and editor may be null if a prototypical instance for a
 * <mxDefaultKeyHandlerCodec> is created.
 *
 * Parameters:
 *
 * container - DOM node that contains the toolbar.
 * editor - Reference to the enclosing <mxEditor>. 
 */
function mxDefaultToolbar(container, editor)
{
\tthis.editor = editor;

\tif (container != null && editor != null)
\t{
\t\tthis.init(container);
\t}
};
\t
/**
 * Variable: editor
 *
 * Reference to the enclosing <mxEditor>.
 */
mxDefaultToolbar.prototype.editor = null;

/**
 * Variable: toolbar
 *
 * Holds the internal <mxToolbar>.
 */
mxDefaultToolbar.prototype.toolbar = null;

/**
 * Variable: resetHandler
 *
 * Reference to the function used to reset the <toolbar>.
 */
mxDefaultToolbar.prototype.resetHandler = null;

/**
 * Variable: spacing
 *
 * Defines the spacing between existing and new vertices in
 * gridSize units when a new vertex is dropped on an existing
 * cell. Default is 4 (40 pixels).
 */
mxDefaultToolbar.prototype.spacing = 4;

/**
 * Variable: connectOnDrop
 * 
 * Specifies if elements should be connected if new cells are dropped onto
 * connectable elements. Default is false.
 */
mxDefaultToolbar.prototype.connectOnDrop = false;

/**
 * Function: init
 * 
 * Constructs the <toolbar> for the given container and installs a listener
 * that updates the <mxEditor.insertFunction> on <editor> if an item is
 * selected in the toolbar. This assumes that <editor> is not null.
 *
 * Parameters:
 *
 * container - DOM node that contains the toolbar.
 */
mxDefaultToolbar.prototype.init = function(container)
{
\tif (container != null)
\t{
\t\tthis.toolbar = new mxToolbar(container);
\t\t
\t\t// Installs the insert function in the editor if an item is
\t\t// selected in the toolbar
\t\tthis.toolbar.addListener(mxEvent.SELECT, mxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tvar funct = evt.getProperty('function');
\t\t\t
\t\t\tif (funct != null)
\t\t\t{
\t\t\t\tthis.editor.insertFunction = mxUtils.bind(this, function()
\t\t\t\t{
\t\t\t\t\tfunct.apply(this, arguments);
\t\t\t\t\tthis.toolbar.resetMode();
\t\t\t\t});
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tthis.editor.insertFunction = null;
\t\t\t}
\t\t}));
\t\t
\t\t// Resets the selected tool after a doubleclick or escape keystroke
\t\tthis.resetHandler = mxUtils.bind(this, function()
\t\t{
\t\t\tif (this.toolbar != null)
\t\t\t{
\t\t\t\tthis.toolbar.resetMode(true);
\t\t\t}
\t\t});

\t\tthis.editor.graph.addListener(mxEvent.DOUBLE_CLICK, this.resetHandler);
\t\tthis.editor.addListener(mxEvent.ESCAPE, this.resetHandler);
\t}
};

/**
 * Function: addItem
 *
 * Adds a new item that executes the given action in <editor>. The title,
 * icon and pressedIcon are used to display the toolbar item.
 * 
 * Parameters:
 *
 * title - String that represents the title (tooltip) for the item.
 * icon - URL of the icon to be used for displaying the item.
 * action - Name of the action to execute when the item is clicked.
 * pressed - Optional URL of the icon for the pressed state.
 */
mxDefaultToolbar.prototype.addItem = function(title, icon, action, pressed)
{
\tvar clickHandler = mxUtils.bind(this, function()
\t{
\t\tif (action != null && action.length > 0)
\t\t{
\t\t\tthis.editor.execute(action);
\t\t}
\t});
\t
\treturn this.toolbar.addItem(title, icon, clickHandler, pressed);
};

/**
 * Function: addSeparator
 *
 * Adds a vertical separator using the optional icon.
 * 
 * Parameters:
 * 
 * icon - Optional URL of the icon that represents the vertical separator.
 * Default is <mxClient.imageBasePath> + '/separator.gif'.
 */
mxDefaultToolbar.prototype.addSeparator = function(icon)
{
\ticon = icon || mxClient.imageBasePath + '/separator.gif';
\tthis.toolbar.addSeparator(icon);
};
\t
/**
 * Function: addCombo
 *
 * Helper method to invoke <mxToolbar.addCombo> on <toolbar> and return the
 * resulting DOM node.
 */
mxDefaultToolbar.prototype.addCombo = function()
{
\treturn this.toolbar.addCombo();
};
\t\t
/**
 * Function: addActionCombo
 *
 * Helper method to invoke <mxToolbar.addActionCombo> on <toolbar> using
 * the given title and return the resulting DOM node.
 * 
 * Parameters:
 * 
 * title - String that represents the title of the combo.
 */
mxDefaultToolbar.prototype.addActionCombo = function(title)
{
\treturn this.toolbar.addActionCombo(title);
};

/**
 * Function: addActionOption
 *
 * Binds the given action to a option with the specified label in the
 * given combo. Combo is an object returned from an earlier call to
 * <addCombo> or <addActionCombo>.
 * 
 * Parameters:
 * 
 * combo - DOM node that represents the combo box.
 * title - String that represents the title of the combo.
 * action - Name of the action to execute in <editor>.
 */
mxDefaultToolbar.prototype.addActionOption = function(combo, title, action)
{
\tvar clickHandler = mxUtils.bind(this, function()
\t{
\t\tthis.editor.execute(action);
\t});
\t
\tthis.addOption(combo, title, clickHandler);
};

/**
 * Function: addOption
 *
 * Helper method to invoke <mxToolbar.addOption> on <toolbar> and return
 * the resulting DOM node that represents the option.
 * 
 * Parameters:
 * 
 * combo - DOM node that represents the combo box.
 * title - String that represents the title of the combo.
 * value - Object that represents the value of the option.
 */
mxDefaultToolbar.prototype.addOption = function(combo, title, value)
{
\treturn this.toolbar.addOption(combo, title, value);
};
\t
/**
 * Function: addMode
 *
 * Creates an item for selecting the given mode in the <editor>'s graph.
 * Supported modenames are select, connect and pan.
 * 
 * Parameters:
 * 
 * title - String that represents the title of the item.
 * icon - URL of the icon that represents the item.
 * mode - String that represents the mode name to be used in
 * <mxEditor.setMode>.
 * pressed - Optional URL of the icon that represents the pressed state.
 * funct - Optional JavaScript function that takes the <mxEditor> as the
 * first and only argument that is executed after the mode has been
 * selected.
 */
mxDefaultToolbar.prototype.addMode = function(title, icon, mode, pressed, funct)
{
\tvar clickHandler = mxUtils.bind(this, function()
\t{
\t\tthis.editor.setMode(mode);
\t\t
\t\tif (funct != null)
\t\t{
\t\t\tfunct(this.editor);
\t\t}
\t});
\t
\treturn this.toolbar.addSwitchMode(title, icon, clickHandler, pressed);
};

/**
 * Function: addPrototype
 *
 * Creates an item for inserting a clone of the specified prototype cell into
 * the <editor>'s graph. The ptype may either be a cell or a function that
 * returns a cell.
 * 
 * Parameters:
 * 
 * title - String that represents the title of the item.
 * icon - URL of the icon that represents the item.
 * ptype - Function or object that represents the prototype cell. If ptype
 * is a function then it is invoked with no arguments to create new
 * instances.
 * pressed - Optional URL of the icon that represents the pressed state.
 * insert - Optional JavaScript function that handles an insert of the new
 * cell. This function takes the <mxEditor>, new cell to be inserted, mouse
 * event and optional <mxCell> under the mouse pointer as arguments.
 * toggle - Optional boolean that specifies if the item can be toggled.
 * Default is true.
 */
mxDefaultToolbar.prototype.addPrototype = function(title, icon, ptype, pressed, insert, toggle)
{
\t// Creates a wrapper function that is in charge of constructing
\t// the new cell instance to be inserted into the graph
\tvar factory = mxUtils.bind(this, function()
\t{
\t\tif (typeof(ptype) == 'function')
\t\t{
\t\t\treturn ptype();
\t\t}
\t\telse if (ptype != null)
\t\t{
\t\t\treturn this.editor.graph.cloneCell(ptype);
\t\t}
\t\t
\t\treturn null;
\t});
\t
\t// Defines the function for a click event on the graph
\t// after this item has been selected in the toolbar
\tvar clickHandler = mxUtils.bind(this, function(evt, cell)
\t{
\t\tif (typeof(insert) == 'function')
\t\t{
\t\t\tinsert(this.editor, factory(), evt, cell);
\t\t}
\t\telse
\t\t{
\t\t\tthis.drop(factory(), evt, cell);
\t\t}
\t\t
\t\tthis.toolbar.resetMode();
\t\tmxEvent.consume(evt);
\t});
\t
\tvar img = this.toolbar.addMode(title, icon, clickHandler, pressed, null, toggle);
\t\t\t\t
\t// Creates a wrapper function that calls the click handler without
\t// the graph argument
\tvar dropHandler = function(graph, evt, cell)
\t{
\t\tclickHandler(evt, cell);
\t};
\t
\tthis.installDropHandler(img, dropHandler);
\t
\treturn img;
};

/**
 * Function: drop
 * 
 * Handles a drop from a toolbar item to the graph. The given vertex
 * represents the new cell to be inserted. This invokes <insert> or
 * <connect> depending on the given target cell.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> to be inserted.
 * evt - Mouse event that represents the drop.
 * target - Optional <mxCell> that represents the drop target.
 */
mxDefaultToolbar.prototype.drop = function(vertex, evt, target)
{
\tvar graph = this.editor.graph;
\tvar model = graph.getModel();
\t
\tif (target == null ||
\t\tmodel.isEdge(target) ||
\t\t!this.connectOnDrop ||
\t\t!graph.isCellConnectable(target))
\t{
\t\twhile (target != null &&
\t\t\t!graph.isValidDropTarget(target, [vertex], evt))
\t\t{
\t\t\ttarget = model.getParent(target);
\t\t}
\t\t
\t\tthis.insert(vertex, evt, target);
\t}
\telse
\t{
\t\tthis.connect(vertex, evt, target);
\t}
};

/**
 * Function: insert
 *
 * Handles a drop by inserting the given vertex into the given parent cell
 * or the default parent if no parent is specified.
 * 
 * Parameters:
 * 
 * vertex - <mxCell> to be inserted.
 * evt - Mouse event that represents the drop.
 * parent - Optional <mxCell> that represents the parent.
 */
mxDefaultToolbar.prototype.insert = function(vertex, evt, target)
{
\tvar graph = this.editor.graph;
\t
\tif (graph.canImportCell(vertex))
\t{
\t\tvar x = mxEvent.getClientX(evt);
\t\tvar y = mxEvent.getClientY(evt);
\t\tvar pt = mxUtils.convertPoint(graph.container, x, y);
\t\t
\t\t// Splits the target edge or inserts into target group
\t\tif (graph.isSplitEnabled() &&
\t\t\tgraph.isSplitTarget(target, [vertex], evt))
\t\t{
\t\t\treturn graph.splitEdge(target, [vertex], null, pt.x, pt.y);
\t\t}
\t\telse
\t\t{
\t\t\treturn this.editor.addVertex(target, vertex, pt.x, pt.y);
\t\t}
\t}
\t
\treturn null;
};

/**
 * Function: connect
 * 
 * Handles a drop by connecting the given vertex to the given source cell.
 * 
 * vertex - <mxCell> to be inserted.
 * evt - Mouse event that represents the drop.
 * source - Optional <mxCell> that represents the source terminal.
 */
mxDefaultToolbar.prototype.connect = function(vertex, evt, source)
{
\tvar graph = this.editor.graph;
\tvar model = graph.getModel();
\t
\tif (source != null &&
\t\tgraph.isCellConnectable(vertex) &&
\t\tgraph.isEdgeValid(null, source, vertex))
\t{
\t\tvar edge = null;

\t\tmodel.beginUpdate();
\t\ttry
\t\t{
\t\t\tvar geo = model.getGeometry(source);
\t\t\tvar g = model.getGeometry(vertex).clone();
\t\t\t
\t\t\t// Moves the vertex away from the drop target that will
\t\t\t// be used as the source for the new connection
\t\t\tg.x = geo.x + (geo.width - g.width) / 2;
\t\t\tg.y = geo.y + (geo.height - g.height) / 2;
\t\t\t
\t\t\tvar step = this.spacing * graph.gridSize;
\t\t\tvar dist = model.getDirectedEdgeCount(source, true) * 20;
\t\t\t
\t\t\tif (this.editor.horizontalFlow)
\t\t\t{
\t\t\t\tg.x += (g.width + geo.width) / 2 + step + dist;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tg.y += (g.height + geo.height) / 2 + step + dist;
\t\t\t}
\t\t\t
\t\t\tvertex.setGeometry(g);
\t\t\t
\t\t\t// Fires two add-events with the code below - should be fixed
\t\t\t// to only fire one add event for both inserts
\t\t\tvar parent = model.getParent(source);
\t\t\tgraph.addCell(vertex, parent);
\t\t\tgraph.constrainChild(vertex);

\t\t\t// Creates the edge using the editor instance and calls
\t\t\t// the second function that fires an add event
\t\t\tedge = this.editor.createEdge(source, vertex);
\t\t\t
\t\t\tif (model.getGeometry(edge) == null)
\t\t\t{
\t\t\t\tvar edgeGeometry = new mxGeometry();
\t\t\t\tedgeGeometry.relative = true;
\t\t\t\t
\t\t\t\tmodel.setGeometry(edge, edgeGeometry);
\t\t\t}
\t\t\t
\t\t\tgraph.addEdge(edge, parent, source, vertex);
\t\t}
\t\tfinally
\t\t{
\t\t\tmodel.endUpdate();
\t\t}
\t\t
\t\tgraph.setSelectionCells([vertex, edge]);
\t\tgraph.scrollCellToVisible(vertex);
\t}
};

/**
 * Function: installDropHandler
 * 
 * Makes the given img draggable using the given function for handling a
 * drop event.
 * 
 * Parameters:
 * 
 * img - DOM node that represents the image.
 * dropHandler - Function that handles a drop of the image.
 */
mxDefaultToolbar.prototype.installDropHandler = function (img, dropHandler)
{
\tvar sprite = document.createElement('img');
\tsprite.setAttribute('src', img.getAttribute('src'));

\t// Handles delayed loading of the images
\tvar loader = mxUtils.bind(this, function(evt)
\t{
\t\t// Preview uses the image node with double size. Later this can be
\t\t// changed to use a separate preview and guides, but for this the
\t\t// dropHandler must use the additional x- and y-arguments and the
\t\t// dragsource which makeDraggable returns much be configured to
\t\t// use guides via mxDragSource.isGuidesEnabled.
\t\tsprite.style.width = (2 * img.offsetWidth) + 'px';
\t\tsprite.style.height = (2 * img.offsetHeight) + 'px';

\t\tmxUtils.makeDraggable(img, this.editor.graph, dropHandler,
\t\t\tsprite);
\t\tmxEvent.removeListener(sprite, 'load', loader);
\t});

\tif (mxClient.IS_IE)
\t{
\t\tloader();
\t}
\telse
\t{
\t\tmxEvent.addListener(sprite, 'load', loader);
\t}\t
};

/**
 * Function: destroy
 * 
 * Destroys the <toolbar> associated with this object and removes all
 * installed listeners. This does normally not need to be called, the
 * <toolbar> is destroyed automatically when the window unloads (in IE) by
 * <mxEditor>.
 */
mxDefaultToolbar.prototype.destroy = function ()
{
\tif (this.resetHandler != null)
\t{
\t\tthis.editor.graph.removeListener('dblclick', this.resetHandler);
\t\tthis.editor.removeListener('escape', this.resetHandler);
\t\tthis.resetHandler = null;
\t}
\t
\tif (this.toolbar != null)
\t{
\t\tthis.toolbar.destroy();
\t\tthis.toolbar = null;
\t}
};
/**
 * Copyright (c) 2006-2019, JGraph Ltd
 * Copyright (c) 2006-2019, draw.io AG
 */
/**
 * Class: mxEditor
 *
 * Extends <mxEventSource> to implement an application wrapper for a graph that
 * adds <actions>, I/O using <mxCodec>, auto-layout using <mxLayoutManager>,
 * command history using <undoManager>, and standard dialogs and widgets, eg.
 * properties, help, outline, toolbar, and popupmenu. It also adds <templates>
 * to be used as cells in toolbars, auto-validation using the <validation>
 * flag, attribute cycling using <cycleAttributeValues>, higher-level events
 * such as <root>, and backend integration using <urlPost> and <urlImage>.
 *
 * Actions:
 *
 * Actions are functions stored in the <actions> array under their names. The
 * functions take the <mxEditor> as the first, and an optional <mxCell> as the
 * second argument and are invoked using <execute>. Any additional arguments
 * passed to execute are passed on to the action as-is.
 *
 * A list of built-in actions is available in the <addActions> description.
 *
 * Read/write Diagrams:
 *
 * To read a diagram from an XML string, for example from a textfield within the
 * page, the following code is used:
 *
 * (code)
 * var doc = mxUtils.parseXML(xmlString);
 * var node = doc.documentElement;
 * editor.readGraphModel(node);
 * (end)
 *
 * For reading a diagram from a remote location, use the <open> method.
 *
 * To save diagrams in XML on a server, you can set the <urlPost> variable.
 * This variable will be used in <getUrlPost> to construct a URL for the post
 * request that is issued in the <save> method. The post request contains the
 * XML representation of the diagram as returned by <writeGraphModel> in the
 * xml parameter.
 *
 * On the server side, the post request is processed using standard
 * technologies such as Java Servlets, CGI, .NET or ASP.
 *
 * Here are some examples of processing a post request in various languages.
 *
 * - Java: URLDecoder.decode(request.getParameter(\"xml\"), \"UTF-8\").replace(\"\\n\", \"&#xa;\")
 *
 * Note that the linefeeds should only be replaced if the XML is
 * processed in Java, for example when creating an image, but not
 * if the XML is passed back to the client-side.
 *
 * - .NET: HttpUtility.UrlDecode(context.Request.Params[\"xml\"])
 * - PHP: urldecode(\$_POST[\"xml\"])
 *
 * Creating images:
 *
 * A backend (Java, PHP or C#) is required for creating images. The
 * distribution contains an example for each backend (ImageHandler.java,
 * ImageHandler.cs and graph.php). More information about using a backend
 * to create images can be found in the readme.html files. Note that the
 * preview is implemented using VML/SVG in the browser and does not require
 * a backend. The backend is only required to creates images (bitmaps).
 *
 * Special characters:
 *
 * Note There are five characters that should always appear in XML content as
 * escapes, so that they do not interact with the syntax of the markup. These
 * are part of the language for all documents based on XML and for HTML.
 *
 * - &lt; (<)
 * - &gt; (>)
 * - &amp; (&)
 * - &quot; (\")
 * - &apos; (')
 *
 * Although it is part of the XML language, &apos; is not defined in HTML.
 * For this reason the XHTML specification recommends instead the use of
 * &#39; if text may be passed to a HTML user agent.
 *
 * If you are having problems with special characters on the server-side then
 * you may want to try the <escapePostData> flag.
 *
 * For converting decimal escape sequences inside strings, a user has provided
 * us with the following function:
 *
 * (code)
 * function html2js(text)
 * {
 *   var entitySearch = /&#[0-9]+;/;
 *   var entity;
 *
 *   while (entity = entitySearch.exec(text))
 *   {
 *     var charCode = entity[0].substring(2, entity[0].length -1);
 *     text = text.substring(0, entity.index)
 *            + String.fromCharCode(charCode)
 *            + text.substring(entity.index + entity[0].length);
 *   }
 *
 *   return text;
 * }
 * (end)
 *
 * Otherwise try using hex escape sequences and the built-in unescape function
 * for converting such strings.
 *
 * Local Files:
 *
 * For saving and opening local files, no standardized method exists that
 * works across all browsers. The recommended way of dealing with local files
 * is to create a backend that streams the XML data back to the browser (echo)
 * as an attachment so that a Save-dialog is displayed on the client-side and
 * the file can be saved to the local disk.
 *
 * For example, in PHP the code that does this looks as follows.
 *
 * (code)
 * \$xml = stripslashes(\$_POST[\"xml\"]);
 * header(\"Content-Disposition: attachment; filename=\\\"diagram.xml\\\"\");
 * echo(\$xml);
 * (end)
 *
 * To open a local file, the file should be uploaded via a form in the browser
 * and then opened from the server in the editor.
 *
 * Cell Properties:
 *
 * The properties displayed in the properties dialog are the attributes and
 * values of the cell's user object, which is an XML node. The XML node is
 * defined in the templates section of the config file.
 *
 * The templates are stored in <mxEditor.templates> and contain cells which
 * are cloned at insertion time to create new vertices by use of drag and
 * drop from the toolbar. Each entry in the toolbar for adding a new vertex
 * must refer to an existing template.
 *
 * In the following example, the task node is a business object and only the
 * mxCell node and its mxGeometry child contain graph information:
 *
 * (code)
 * <Task label=\"Task\" description=\"\">
 *   <mxCell vertex=\"true\">
 *     <mxGeometry as=\"geometry\" width=\"72\" height=\"32\"/>
 *   </mxCell>
 * </Task>
 * (end)
 *
 * The idea is that the XML representation is inverse from the in-memory
 * representation: The outer XML node is the user object and the inner node is
 * the cell. This means the user object of the cell is the Task node with no
 * children for the above example:
 *
 * (code)
 * <Task label=\"Task\" description=\"\"/>
 * (end)
 *
 * The Task node can have any tag name, attributes and child nodes. The
 * <mxCodec> will use the XML hierarchy as the user object, while removing the
 * \"known annotations\", such as the mxCell node. At save-time the cell data
 * will be \"merged\" back into the user object. The user object is only modified
 * via the properties dialog during the lifecycle of the cell.
 *
 * In the default implementation of <createProperties>, the user object's
 * attributes are put into a form for editing. Attributes are changed using
 * the <mxCellAttributeChange> action in the model. The dialog can be replaced
 * by overriding the <createProperties> hook or by replacing the showProperties
 * action in <actions>. Alternatively, the entry in the config file's popupmenu
 * section can be modified to invoke a different action.
 *
 * If you want to displey the properties dialog on a doubleclick, you can set
 * <mxEditor.dblClickAction> to showProperties as follows:
 *
 * (code)
 * editor.dblClickAction = 'showProperties';
 * (end)
 *
 * Popupmenu and Toolbar:
 *
 * The toolbar and popupmenu are typically configured using the respective
 * sections in the config file, that is, the popupmenu is defined as follows:
 *
 * (code)
 * <mxEditor>
 *   <mxDefaultPopupMenu as=\"popupHandler\">
 * \t\t<add as=\"cut\" action=\"cut\" icon=\"images/cut.gif\"/>
 *      ...
 * (end)
 *
 * New entries can be added to the toolbar by inserting an add-node into the
 * above configuration. Existing entries may be removed and changed by
 * modifying or removing the respective entries in the configuration.
 * The configuration is read by the <mxDefaultPopupMenuCodec>, the format of the
 * configuration is explained in <mxDefaultPopupMenu.decode>.
 *
 * The toolbar is defined in the mxDefaultToolbar section. Items can be added
 * and removed in this section.
 *
 * (code)
 * <mxEditor>
 *   <mxDefaultToolbar>
 *     <add as=\"save\" action=\"save\" icon=\"images/save.gif\"/>
 *     <add as=\"Swimlane\" template=\"swimlane\" icon=\"images/swimlane.gif\"/>
 *     ...
 * (end)
 *
 * The format of the configuration is described in
 * <mxDefaultToolbarCodec.decode>.
 *
 * Ids:
 *
 * For the IDs, there is an implicit behaviour in <mxCodec>: It moves the Id
 * from the cell to the user object at encoding time and vice versa at decoding
 * time. For example, if the Task node from above has an id attribute, then
 * the <mxCell.id> of the corresponding cell will have this value. If there
 * is no Id collision in the model, then the cell may be retrieved using this
 * Id with the <mxGraphModel.getCell> function. If there is a collision, a new
 * Id will be created for the cell using <mxGraphModel.createId>. At encoding
 * time, this new Id will replace the value previously stored under the id
 * attribute in the Task node.
 *
 * See <mxEditorCodec>, <mxDefaultToolbarCodec> and <mxDefaultPopupMenuCodec>
 * for information about configuring the editor and user interface.
 *
 * Programmatically inserting cells:
 *
 * For inserting a new cell, say, by clicking a button in the document,
 * the following code can be used. This requires an reference to the editor.
 *
 * (code)
 * var userObject = new Object();
 * var parent = editor.graph.getDefaultParent();
 * var model = editor.graph.model;
 * model.beginUpdate();
 * try
 * {
 *   editor.graph.insertVertex(parent, null, userObject, 20, 20, 80, 30);
 * }
 * finally
 * {
 *   model.endUpdate();
 * }
 * (end)
 *
 * If a template cell from the config file should be inserted, then a clone
 * of the template can be created as follows. The clone is then inserted using
 * the add function instead of addVertex.
 *
 * (code)
 * var template = editor.templates['task'];
 * var clone = editor.graph.model.cloneCell(template);
 * (end)
 *
 * Resources:
 *
 * resources/editor - Language resources for mxEditor
 *
 * Callback: onInit
 *
 * Called from within the constructor. In the callback,
 * \"this\" refers to the editor instance.
 *
 * Cookie: mxgraph=seen
 *
 * Set when the editor is started. Never expires. Use
 * <resetFirstTime> to reset this cookie. This cookie
 * only exists if <onInit> is implemented.
 *
 * Event: mxEvent.OPEN
 *
 * Fires after a file was opened in <open>. The <code>filename</code> property
 * contains the filename that was used. The same value is also available in
 * <filename>.
 *
 * Event: mxEvent.SAVE
 *
 * Fires after the current file was saved in <save>. The <code>url</code>
 * property contains the URL that was used for saving.
 *
 * Event: mxEvent.POST
 *
 * Fires if a successful response was received in <postDiagram>. The
 * <code>request</code> property contains the <mxXmlRequest>, the
 * <code>url</code> and <code>data</code> properties contain the URL and the
 * data that were used in the post request.
 *
 * Event: mxEvent.ROOT
 *
 * Fires when the current root has changed, or when the title of the current
 * root has changed. This event has no properties.
 *
 * Event: mxEvent.BEFORE_ADD_VERTEX
 *
 * Fires before a vertex is added in <addVertex>. The <code>vertex</code>
 * property contains the new vertex and the <code>parent</code> property
 * contains its parent.
 *
 * Event: mxEvent.ADD_VERTEX
 *
 * Fires between begin- and endUpdate in <addVertex>. The <code>vertex</code>
 * property contains the vertex that is being inserted.
 *
 * Event: mxEvent.AFTER_ADD_VERTEX
 *
 * Fires after a vertex was inserted and selected in <addVertex>. The
 * <code>vertex</code> property contains the new vertex.
 *
 * Example:
 *
 * For starting an in-place edit after a new vertex has been added to the
 * graph, the following code can be used.
 *
 * (code)
 * editor.addListener(mxEvent.AFTER_ADD_VERTEX, function(sender, evt)
 * {
 *   var vertex = evt.getProperty('vertex');
 *
 *   if (editor.graph.isCellEditable(vertex))
 *   {
 *   \teditor.graph.startEditingAtCell(vertex);
 *   }
 * });
 * (end)
 *
 * Event: mxEvent.ESCAPE
 *
 * Fires when the escape key is pressed. The <code>event</code> property
 * contains the key event.
 *
 * Constructor: mxEditor
 *
 * Constructs a new editor. This function invokes the <onInit> callback
 * upon completion.
 *
 * Example:
 *
 * (code)
 * var config = mxUtils.load('config/diagrameditor.xml').getDocumentElement();
 * var editor = new mxEditor(config);
 * (end)
 *
 * Parameters:
 *
 * config - Optional XML node that contains the configuration.
 */
function mxEditor(config)
{
\tthis.actions = [];
\tthis.addActions();

\t// Executes the following only if a document has been instanciated.
\t// That is, don't execute when the editorcodec is setup.
\tif (document.body != null)
\t{
\t\t// Defines instance fields
\t\tthis.cycleAttributeValues = [];
\t\tthis.popupHandler = new mxDefaultPopupMenu();
\t\tthis.undoManager = new mxUndoManager();

\t\t// Creates the graph and toolbar without the containers
\t\tthis.graph = this.createGraph();
\t\tthis.toolbar = this.createToolbar();

\t\t// Creates the global keyhandler (requires graph instance)
\t\tthis.keyHandler = new mxDefaultKeyHandler(this);

\t\t// Configures the editor using the URI
\t\t// which was passed to the ctor
\t\tthis.configure(config);

\t\t// Assigns the swimlaneIndicatorColorAttribute on the graph
\t\tthis.graph.swimlaneIndicatorColorAttribute = this.cycleAttributeName;

\t\t// Checks if the <onInit> hook has been set
\t\tif (this.onInit != null)
\t\t{
\t\t\t// Invokes the <onInit> hook
\t\t\tthis.onInit();
\t\t}

\t\t// Automatic deallocation of memory
\t\tif (mxClient.IS_IE)
\t\t{
\t\t\tmxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
\t\t\t{
\t\t\t\tthis.destroy();
\t\t\t}));
\t\t}
\t}
};

/**
 * Installs the required language resources at class
 * loading time.
 */
if (mxLoadResources)
{
\tmxResources.add(mxClient.basePath + '/resources/editor');
}
else
{
\tmxClient.defaultBundles.push(mxClient.basePath + '/resources/editor');
}

/**
 * Extends mxEventSource.
 */
mxEditor.prototype = new mxEventSource();
mxEditor.prototype.constructor = mxEditor;

/**
 * Group: Controls and Handlers
 */

/**
 * Variable: askZoomResource
 *
 * Specifies the resource key for the zoom dialog. If the resource for this
 * key does not exist then the value is used as the error message. Default
 * is 'askZoom'.
 */
mxEditor.prototype.askZoomResource = (mxClient.language != 'none') ? 'askZoom' : '';

/**
 * Variable: lastSavedResource
 *
 * Specifies the resource key for the last saved info. If the resource for
 * this key does not exist then the value is used as the error message.
 * Default is 'lastSaved'.
 */
mxEditor.prototype.lastSavedResource = (mxClient.language != 'none') ? 'lastSaved' : '';

/**
 * Variable: currentFileResource
 *
 * Specifies the resource key for the current file info. If the resource for
 * this key does not exist then the value is used as the error message.
 * Default is 'currentFile'.
 */
mxEditor.prototype.currentFileResource = (mxClient.language != 'none') ? 'currentFile' : '';

/**
 * Variable: propertiesResource
 *
 * Specifies the resource key for the properties window title. If the
 * resource for this key does not exist then the value is used as the
 * error message. Default is 'properties'.
 */
mxEditor.prototype.propertiesResource = (mxClient.language != 'none') ? 'properties' : '';

/**
 * Variable: tasksResource
 *
 * Specifies the resource key for the tasks window title. If the
 * resource for this key does not exist then the value is used as the
 * error message. Default is 'tasks'.
 */
mxEditor.prototype.tasksResource = (mxClient.language != 'none') ? 'tasks' : '';

/**
 * Variable: helpResource
 *
 * Specifies the resource key for the help window title. If the
 * resource for this key does not exist then the value is used as the
 * error message. Default is 'help'.
 */
mxEditor.prototype.helpResource = (mxClient.language != 'none') ? 'help' : '';

/**
 * Variable: outlineResource
 *
 * Specifies the resource key for the outline window title. If the
 * resource for this key does not exist then the value is used as the
 * error message. Default is 'outline'.
 */
mxEditor.prototype.outlineResource = (mxClient.language != 'none') ? 'outline' : '';

/**
 * Variable: outline
 *
 * Reference to the <mxWindow> that contains the outline. The <mxOutline>
 * is stored in outline.outline.
 */
mxEditor.prototype.outline = null;

/**
 * Variable: graph
 *
 * Holds a <mxGraph> for displaying the diagram. The graph
 * is created in <setGraphContainer>.
 */
mxEditor.prototype.graph = null;

/**
 * Variable: graphRenderHint
 *
 * Holds the render hint used for creating the
 * graph in <setGraphContainer>. See <mxGraph>.
 * Default is null.
 */
mxEditor.prototype.graphRenderHint = null;

/**
 * Variable: toolbar
 *
 * Holds a <mxDefaultToolbar> for displaying the toolbar. The
 * toolbar is created in <setToolbarContainer>.
 */
mxEditor.prototype.toolbar = null;

/**
 * Variable: status
 *
 * DOM container that holds the statusbar. Default is null.
 * Use <setStatusContainer> to set this value.
 */
mxEditor.prototype.status = null;

/**
 * Variable: popupHandler
 *
 * Holds a <mxDefaultPopupMenu> for displaying
 * popupmenus.
 */
mxEditor.prototype.popupHandler = null;

/**
 * Variable: undoManager
 *
 * Holds an <mxUndoManager> for the command history.
 */
mxEditor.prototype.undoManager = null;

/**
 * Variable: keyHandler
 *
 * Holds a <mxDefaultKeyHandler> for handling keyboard events.
 * The handler is created in <setGraphContainer>.
 */
mxEditor.prototype.keyHandler = null;

/**
 * Group: Actions and Options
 */

/**
 * Variable: actions
 *
 * Maps from actionnames to actions, which are functions taking
 * the editor and the cell as arguments. Use <addAction>
 * to add or replace an action and <execute> to execute an action
 * by name, passing the cell to be operated upon as the second
 * argument.
 */
mxEditor.prototype.actions = null;

/**
 * Variable: dblClickAction
 *
 * Specifies the name of the action to be executed
 * when a cell is double clicked. Default is 'edit'.
 *
 * To handle a singleclick, use the following code.
 *
 * (code)
 * editor.graph.addListener(mxEvent.CLICK, function(sender, evt)
 * {
 *   var e = evt.getProperty('event');
 *   var cell = evt.getProperty('cell');
 *
 *   if (cell != null && !e.isConsumed())
 *   {
 *     // Do something useful with cell...
 *     e.consume();
 *   }
 * });
 * (end)
 */
mxEditor.prototype.dblClickAction = 'edit';

/**
 * Variable: swimlaneRequired
 *
 * Specifies if new cells must be inserted
 * into an existing swimlane. Otherwise, cells
 * that are not swimlanes can be inserted as
 * top-level cells. Default is false.
 */
mxEditor.prototype.swimlaneRequired = false;

/**
 * Variable: disableContextMenu
 *
 * Specifies if the context menu should be disabled in the graph container.
 * Default is true.
 */
mxEditor.prototype.disableContextMenu = true;

/**
 * Group: Templates
 */

/**
 * Variable: insertFunction
 *
 * Specifies the function to be used for inserting new
 * cells into the graph. This is assigned from the
 * <mxDefaultToolbar> if a vertex-tool is clicked.
 */
mxEditor.prototype.insertFunction = null;

/**
 * Variable: forcedInserting
 *
 * Specifies if a new cell should be inserted on a single
 * click even using <insertFunction> if there is a cell
 * under the mousepointer, otherwise the cell under the
 * mousepointer is selected. Default is false.
 */
mxEditor.prototype.forcedInserting = false;

/**
 * Variable: templates
 *
 * Maps from names to protoype cells to be used
 * in the toolbar for inserting new cells into
 * the diagram.
 */
mxEditor.prototype.templates = null;

/**
 * Variable: defaultEdge
 *
 * Prototype edge cell that is used for creating
 * new edges.
 */
mxEditor.prototype.defaultEdge = null;

/**
 * Variable: defaultEdgeStyle
 *
 * Specifies the edge style to be returned in <getEdgeStyle>.
 * Default is null.
 */
mxEditor.prototype.defaultEdgeStyle = null;

/**
 * Variable: defaultGroup
 *
 * Prototype group cell that is used for creating
 * new groups.
 */
mxEditor.prototype.defaultGroup = null;

/**
 * Variable: groupBorderSize
 *
 * Default size for the border of new groups. If null,
 * then then <mxGraph.gridSize> is used. Default is
 * null.
 */
mxEditor.prototype.groupBorderSize = null;

/**
 * Group: Backend Integration
 */

/**
 * Variable: filename
 *
 * Contains the URL of the last opened file as a string.
 * Default is null.
 */
mxEditor.prototype.filename = null;

/**
 * Variable: lineFeed
 *
 * Character to be used for encoding linefeeds in <save>. Default is '&#xa;'.
 */
mxEditor.prototype.linefeed = '&#xa;';

/**
 * Variable: postParameterName
 *
 * Specifies if the name of the post parameter that contains the diagram
 * data in a post request to the server. Default is 'xml'.
 */
mxEditor.prototype.postParameterName = 'xml';

/**
 * Variable: escapePostData
 *
 * Specifies if the data in the post request for saving a diagram
 * should be converted using encodeURIComponent. Default is true.
 */
mxEditor.prototype.escapePostData = true;

/**
 * Variable: urlPost
 *
 * Specifies the URL to be used for posting the diagram
 * to a backend in <save>.
 */
mxEditor.prototype.urlPost = null;

/**
 * Variable: urlImage
 *
 * Specifies the URL to be used for creating a bitmap of
 * the graph in the image action.
 */
mxEditor.prototype.urlImage = null;

/**
 * Group: Autolayout
 */

/**
 * Variable: horizontalFlow
 *
 * Specifies the direction of the flow
 * in the diagram. This is used in the
 * layout algorithms. Default is false,
 * ie. vertical flow.
 */
mxEditor.prototype.horizontalFlow = false;

/**
 * Variable: layoutDiagram
 *
 * Specifies if the top-level elements in the
 * diagram should be layed out using a vertical
 * or horizontal stack depending on the setting
 * of <horizontalFlow>. The spacing between the
 * swimlanes is specified by <swimlaneSpacing>.
 * Default is false.
 *
 * If the top-level elements are swimlanes, then
 * the intra-swimlane layout is activated by
 * the <layoutSwimlanes> switch.
 */
mxEditor.prototype.layoutDiagram = false;

/**
 * Variable: swimlaneSpacing
 *
 * Specifies the spacing between swimlanes if
 * automatic layout is turned on in
 * <layoutDiagram>. Default is 0.
 */
mxEditor.prototype.swimlaneSpacing = 0;

/**
 * Variable: maintainSwimlanes
 *
 * Specifies if the swimlanes should be kept at the same
 * width or height depending on the setting of
 * <horizontalFlow>.  Default is false.
 *
 * For horizontal flows, all swimlanes
 * have the same height and for vertical flows, all swimlanes
 * have the same width. Furthermore, the swimlanes are
 * automatically \"stacked\" if <layoutDiagram> is true.
 */
mxEditor.prototype.maintainSwimlanes = false;

/**
 * Variable: layoutSwimlanes
 *
 * Specifies if the children of swimlanes should
 * be layed out, either vertically or horizontally
 * depending on <horizontalFlow>.
 * Default is false.
 */
mxEditor.prototype.layoutSwimlanes = false;

/**
 * Group: Attribute Cycling
 */

/**
 * Variable: cycleAttributeValues
 *
 * Specifies the attribute values to be cycled when
 * inserting new swimlanes. Default is an empty
 * array.
 */
mxEditor.prototype.cycleAttributeValues = null;

/**
 * Variable: cycleAttributeIndex
 *
 * Index of the last consumed attribute index. If a new
 * swimlane is inserted, then the <cycleAttributeValues>
 * at this index will be used as the value for
 * <cycleAttributeName>. Default is 0.
 */
mxEditor.prototype.cycleAttributeIndex = 0;

/**
 * Variable: cycleAttributeName
 *
 * Name of the attribute to be assigned a <cycleAttributeValues>
 * when inserting new swimlanes. Default is 'fillColor'.
 */
mxEditor.prototype.cycleAttributeName = 'fillColor';

/**
 * Group: Windows
 */

/**
 * Variable: tasks
 *
 * Holds the <mxWindow> created in <showTasks>.
 */
mxEditor.prototype.tasks = null;

/**
 * Variable: tasksWindowImage
 *
 * Icon for the tasks window.
 */
mxEditor.prototype.tasksWindowImage = null;

/**
 * Variable: tasksTop
 *
 * Specifies the top coordinate of the tasks window in pixels.
 * Default is 20.
 */
mxEditor.prototype.tasksTop = 20;

/**
 * Variable: help
 *
 * Holds the <mxWindow> created in <showHelp>.
 */
mxEditor.prototype.help = null;

/**
 * Variable: helpWindowImage
 *
 * Icon for the help window.
 */
mxEditor.prototype.helpWindowImage = null;

/**
 * Variable: urlHelp
 *
 * Specifies the URL to be used for the contents of the
 * Online Help window. This is usually specified in the
 * resources file under urlHelp for language-specific
 * online help support.
 */
mxEditor.prototype.urlHelp = null;

/**
 * Variable: helpWidth
 *
 * Specifies the width of the help window in pixels.
 * Default is 300.
 */
mxEditor.prototype.helpWidth = 300;

/**
 * Variable: helpHeight
 *
 * Specifies the height of the help window in pixels.
 * Default is 260.
 */
mxEditor.prototype.helpHeight = 260;

/**
 * Variable: propertiesWidth
 *
 * Specifies the width of the properties window in pixels.
 * Default is 240.
 */
mxEditor.prototype.propertiesWidth = 240;

/**
 * Variable: propertiesHeight
 *
 * Specifies the height of the properties window in pixels.
 * If no height is specified then the window will be automatically
 * sized to fit its contents. Default is null.
 */
mxEditor.prototype.propertiesHeight = null;

/**
 * Variable: movePropertiesDialog
 *
 * Specifies if the properties dialog should be automatically
 * moved near the cell it is displayed for, otherwise the
 * dialog is not moved. This value is only taken into
 * account if the dialog is already visible. Default is false.
 */
mxEditor.prototype.movePropertiesDialog = false;

/**
 * Variable: validating
 *
 * Specifies if <mxGraph.validateGraph> should automatically be invoked after
 * each change. Default is false.
 */
mxEditor.prototype.validating = false;

/**
 * Variable: modified
 *
 * True if the graph has been modified since it was last saved.
 */
mxEditor.prototype.modified = false;

/**
 * Function: isModified
 *
 * Returns <modified>.
 */
mxEditor.prototype.isModified = function ()
{
\treturn this.modified;
};

/**
 * Function: setModified
 *
 * Sets <modified> to the specified boolean value.
 */
mxEditor.prototype.setModified = function (value)
{
\tthis.modified = value;
};

/**
 * Function: addActions
 *
 * Adds the built-in actions to the editor instance.
 *
 * save - Saves the graph using <urlPost>.
 * print - Shows the graph in a new print preview window.
 * show - Shows the graph in a new window.
 * exportImage - Shows the graph as a bitmap image using <getUrlImage>.
 * refresh - Refreshes the graph's display.
 * cut - Copies the current selection into the clipboard
 * and removes it from the graph.
 * copy - Copies the current selection into the clipboard.
 * paste - Pastes the clipboard into the graph.
 * delete - Removes the current selection from the graph.
 * group - Puts the current selection into a new group.
 * ungroup - Removes the selected groups and selects the children.
 * undo - Undoes the last change on the graph model.
 * redo - Redoes the last change on the graph model.
 * zoom - Sets the zoom via a dialog.
 * zoomIn - Zooms into the graph.
 * zoomOut - Zooms out of the graph
 * actualSize - Resets the scale and translation on the graph.
 * fit - Changes the scale so that the graph fits into the window.
 * showProperties - Shows the properties dialog.
 * selectAll - Selects all cells.
 * selectNone - Clears the selection.
 * selectVertices - Selects all vertices.
 * selectEdges = Selects all edges.
 * edit - Starts editing the current selection cell.
 * enterGroup - Drills down into the current selection cell.
 * exitGroup - Moves up in the drilling hierachy
 * home - Moves to the topmost parent in the drilling hierarchy
 * selectPrevious - Selects the previous cell.
 * selectNext - Selects the next cell.
 * selectParent - Selects the parent of the selection cell.
 * selectChild - Selects the first child of the selection cell.
 * collapse - Collapses the currently selected cells.
 * expand - Expands the currently selected cells.
 * bold - Toggle bold text style.
 * italic - Toggle italic text style.
 * underline - Toggle underline text style.
 * alignCellsLeft - Aligns the selection cells at the left.
 * alignCellsCenter - Aligns the selection cells in the center.
 * alignCellsRight - Aligns the selection cells at the right.
 * alignCellsTop - Aligns the selection cells at the top.
 * alignCellsMiddle - Aligns the selection cells in the middle.
 * alignCellsBottom - Aligns the selection cells at the bottom.
 * alignFontLeft - Sets the horizontal text alignment to left.
 * alignFontCenter - Sets the horizontal text alignment to center.
 * alignFontRight - Sets the horizontal text alignment to right.
 * alignFontTop - Sets the vertical text alignment to top.
 * alignFontMiddle - Sets the vertical text alignment to middle.
 * alignFontBottom - Sets the vertical text alignment to bottom.
 * toggleTasks - Shows or hides the tasks window.
 * toggleHelp - Shows or hides the help window.
 * toggleOutline - Shows or hides the outline window.
 * toggleConsole - Shows or hides the console window.
 */
mxEditor.prototype.addActions = function ()
{
\tthis.addAction('save', function(editor)
\t{
\t\teditor.save();
\t});

\tthis.addAction('print', function(editor)
\t{
\t\tvar preview = new mxPrintPreview(editor.graph, 1);
\t\tpreview.open();
\t});

\tthis.addAction('show', function(editor)
\t{
\t\tmxUtils.show(editor.graph, null, 10, 10);
\t});

\tthis.addAction('exportImage', function(editor)
\t{
\t\tvar url = editor.getUrlImage();

\t\tif (url == null || mxClient.IS_LOCAL)
\t\t{
\t\t\teditor.execute('show');
\t\t}
\t\telse
\t\t{
\t\t\tvar node = mxUtils.getViewXml(editor.graph, 1);
\t\t\tvar xml = mxUtils.getXml(node, '\\n');

\t\t\tmxUtils.submit(url, editor.postParameterName + '=' +
\t\t\t\tencodeURIComponent(xml), document, '_blank');
\t\t}
\t});

\tthis.addAction('refresh', function(editor)
\t{
\t\teditor.graph.refresh();
\t});

\tthis.addAction('cut', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\tmxClipboard.cut(editor.graph);
\t\t}
\t});

\tthis.addAction('copy', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\tmxClipboard.copy(editor.graph);
\t\t}
\t});

\tthis.addAction('paste', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\tmxClipboard.paste(editor.graph);
\t\t}
\t});

\tthis.addAction('delete', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.removeCells();
\t\t}
\t});

\tthis.addAction('group', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setSelectionCell(editor.groupCells());
\t\t}
\t});

\tthis.addAction('ungroup', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setSelectionCells(editor.graph.ungroupCells());
\t\t}
\t});

\tthis.addAction('removeFromParent', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.removeCellsFromParent();
\t\t}
\t});

\tthis.addAction('undo', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.undo();
\t\t}
\t});

\tthis.addAction('redo', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.redo();
\t\t}
\t});

\tthis.addAction('zoomIn', function(editor)
\t{
\t\teditor.graph.zoomIn();
\t});

\tthis.addAction('zoomOut', function(editor)
\t{
\t\teditor.graph.zoomOut();
\t});

\tthis.addAction('actualSize', function(editor)
\t{
\t\teditor.graph.zoomActual();
\t});

\tthis.addAction('fit', function(editor)
\t{
\t\teditor.graph.fit();
\t});

\tthis.addAction('showProperties', function(editor, cell)
\t{
\t\teditor.showProperties(cell);
\t});

\tthis.addAction('selectAll', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectAll();
\t\t}
\t});

\tthis.addAction('selectNone', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.clearSelection();
\t\t}
\t});

\tthis.addAction('selectVertices', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectVertices();
\t\t}
\t});

\tthis.addAction('selectEdges', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectEdges();
\t\t}
\t});

\tthis.addAction('edit', function(editor, cell)
\t{
\t\tif (editor.graph.isEnabled() &&
\t\t\teditor.graph.isCellEditable(cell))
\t\t{
\t\t\teditor.graph.startEditingAtCell(cell);
\t\t}
\t});

\tthis.addAction('toBack', function(editor, cell)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.orderCells(true);
\t\t}
\t});

\tthis.addAction('toFront', function(editor, cell)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.orderCells(false);
\t\t}
\t});

\tthis.addAction('enterGroup', function(editor, cell)
\t{
\t\teditor.graph.enterGroup(cell);
\t});

\tthis.addAction('exitGroup', function(editor)
\t{
\t\teditor.graph.exitGroup();
\t});

\tthis.addAction('home', function(editor)
\t{
\t\teditor.graph.home();
\t});

\tthis.addAction('selectPrevious', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectPreviousCell();
\t\t}
\t});

\tthis.addAction('selectNext', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectNextCell();
\t\t}
\t});

\tthis.addAction('selectParent', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectParentCell();
\t\t}
\t});

\tthis.addAction('selectChild', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.selectChildCell();
\t\t}
\t});

\tthis.addAction('collapse', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.foldCells(true);
\t\t}
\t});

\tthis.addAction('collapseAll', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\tvar cells = editor.graph.getChildVertices();
\t\t\teditor.graph.foldCells(true, false, cells);
\t\t}
\t});

\tthis.addAction('expand', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.foldCells(false);
\t\t}
\t});

\tthis.addAction('expandAll', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\tvar cells = editor.graph.getChildVertices();
\t\t\teditor.graph.foldCells(false, false, cells);
\t\t}
\t});

\tthis.addAction('bold', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.toggleCellStyleFlags(
\t\t\t\tmxConstants.STYLE_FONTSTYLE,
\t\t\t\tmxConstants.FONT_BOLD);
\t\t}
\t});

\tthis.addAction('italic', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.toggleCellStyleFlags(
\t\t\t\tmxConstants.STYLE_FONTSTYLE,
\t\t\t\tmxConstants.FONT_ITALIC);
\t\t}
\t});

\tthis.addAction('underline', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.toggleCellStyleFlags(
\t\t\t\tmxConstants.STYLE_FONTSTYLE,
\t\t\t\tmxConstants.FONT_UNDERLINE);
\t\t}
\t});

\tthis.addAction('alignCellsLeft', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_LEFT);
\t\t}
\t});

\tthis.addAction('alignCellsCenter', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_CENTER);
\t\t}
\t});

\tthis.addAction('alignCellsRight', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_RIGHT);
\t\t}
\t});

\tthis.addAction('alignCellsTop', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_TOP);
\t\t}
\t});

\tthis.addAction('alignCellsMiddle', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_MIDDLE);
\t\t}
\t});

\tthis.addAction('alignCellsBottom', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.alignCells(mxConstants.ALIGN_BOTTOM);
\t\t}
\t});

\tthis.addAction('alignFontLeft', function(editor)
\t{

\t\teditor.graph.setCellStyles(
\t\t\tmxConstants.STYLE_ALIGN,
\t\t\tmxConstants.ALIGN_LEFT);
\t});

\tthis.addAction('alignFontCenter', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setCellStyles(
\t\t\t\tmxConstants.STYLE_ALIGN,
\t\t\t\tmxConstants.ALIGN_CENTER);
\t\t}
\t});

\tthis.addAction('alignFontRight', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setCellStyles(
\t\t\t\tmxConstants.STYLE_ALIGN,
\t\t\t\tmxConstants.ALIGN_RIGHT);
\t\t}
\t});

\tthis.addAction('alignFontTop', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setCellStyles(
\t\t\t\tmxConstants.STYLE_VERTICAL_ALIGN,
\t\t\t\tmxConstants.ALIGN_TOP);
\t\t}
\t});

\tthis.addAction('alignFontMiddle', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setCellStyles(
\t\t\t\tmxConstants.STYLE_VERTICAL_ALIGN,
\t\t\t\tmxConstants.ALIGN_MIDDLE);
\t\t}
\t});

\tthis.addAction('alignFontBottom', function(editor)
\t{
\t\tif (editor.graph.isEnabled())
\t\t{
\t\t\teditor.graph.setCellStyles(
\t\t\t\tmxConstants.STYLE_VERTICAL_ALIGN,
\t\t\t\tmxConstants.ALIGN_BOTTOM);
\t\t}
\t});

\tthis.addAction('zoom', function(editor)
\t{
\t\tvar current = editor.graph.getView().scale*100;
\t\tvar scale = parseFloat(mxUtils.prompt(
\t\t\tmxResources.get(editor.askZoomResource) ||
\t\t\teditor.askZoomResource,
\t\t\tcurrent))/100;

\t\tif (!isNaN(scale))
\t\t{
\t\t\teditor.graph.getView().setScale(scale);
\t\t}
\t});

\tthis.addAction('toggleTasks', function(editor)
\t{
\t\tif (editor.tasks != null)
\t\t{
\t\t\teditor.tasks.setVisible(!editor.tasks.isVisible());
\t\t}
\t\telse
\t\t{
\t\t\teditor.showTasks();
\t\t}
\t});

\tthis.addAction('toggleHelp', function(editor)
\t{
\t\tif (editor.help != null)
\t\t{
\t\t\teditor.help.setVisible(!editor.help.isVisible());
\t\t}
\t\telse
\t\t{
\t\t\teditor.showHelp();
\t\t}
\t});

\tthis.addAction('toggleOutline', function(editor)
\t{
\t\tif (editor.outline == null)
\t\t{
\t\t\teditor.showOutline();
\t\t}
\t\telse
\t\t{
\t\t\teditor.outline.setVisible(!editor.outline.isVisible());
\t\t}
\t});

\tthis.addAction('toggleConsole', function(editor)
\t{
\t\tmxLog.setVisible(!mxLog.isVisible());
\t});
};

/**
 * Function: configure
 *
 * Configures the editor using the specified node. To load the
 * configuration from a given URL the following code can be used to obtain
 * the XML node.
 *
 * (code)
 * var node = mxUtils.load(url).getDocumentElement();
 * (end)
 *
 * Parameters:
 *
 * node - XML node that contains the configuration.
 */
mxEditor.prototype.configure = function (node)
{
\tif (node != null)
\t{
\t\t// Creates a decoder for the XML data
\t\t// and uses it to configure the editor
\t\tvar dec = new mxCodec(node.ownerDocument);
\t\tdec.decode(node, this);

\t\t// Resets the counters, modified state and
\t\t// command history
\t\tthis.resetHistory();
\t}
};

/**
 * Function: resetFirstTime
 *
 * Resets the cookie that is used to remember if the editor has already
 * been used.
 */
mxEditor.prototype.resetFirstTime = function ()
{
\tdocument.cookie =
\t\t'mxgraph=seen; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/';
};

/**
 * Function: resetHistory
 *
 * Resets the command history, modified state and counters.
 */
mxEditor.prototype.resetHistory = function ()
{
\tthis.lastSnapshot = new Date().getTime();
\tthis.undoManager.clear();
\tthis.ignoredChanges = 0;
\tthis.setModified(false);
};

/**
 * Function: addAction
 *
 * Binds the specified actionname to the specified function.
 *
 * Parameters:
 *
 * actionname - String that specifies the name of the action
 * to be added.
 * funct - Function that implements the new action. The first
 * argument of the function is the editor it is used
 * with, the second argument is the cell it operates
 * upon.
 *
 * Example:
 * (code)
 * editor.addAction('test', function(editor, cell)
 * {
 * \t\tmxUtils.alert(\"test \"+cell);
 * });
 * (end)
 */
mxEditor.prototype.addAction = function (actionname, funct)
{
\tthis.actions[actionname] = funct;
};

/**
 * Function: execute
 *
 * Executes the function with the given name in <actions> passing the
 * editor instance and given cell as the first and second argument. All
 * additional arguments are passed to the action as well. This method
 * contains a try-catch block and displays an error message if an action
 * causes an exception. The exception is re-thrown after the error
 * message was displayed.
 *
 * Example:
 *
 * (code)
 * editor.execute(\"showProperties\", cell);
 * (end)
 */
mxEditor.prototype.execute = function (actionname, cell, evt)
{
\tvar action = this.actions[actionname];

\tif (action != null)
\t{
\t\ttry
\t\t{
\t\t\t// Creates the array of arguments by replacing the actionname
\t\t\t// with the editor instance in the args of this function
\t\t\tvar args = arguments;
\t\t\targs[0] = this;

\t\t\t// Invokes the function on the editor using the args
\t\t\taction.apply(this, args);
\t\t}
\t\tcatch (e)
\t\t{
\t\t\tmxUtils.error('Cannot execute ' + actionname +
\t\t\t\t': ' + e.message, 280, true);

\t\t\tthrow e;
\t\t}
\t}
\telse
\t{
\t\tmxUtils.error('Cannot find action '+actionname, 280, true);
\t}
};

/**
 * Function: addTemplate
 *
 * Adds the specified template under the given name in <templates>.
 */
mxEditor.prototype.addTemplate = function (name, template)
{
\tthis.templates[name] = template;
};

/**
 * Function: getTemplate
 *
 * Returns the template for the given name.
 */
mxEditor.prototype.getTemplate = function (name)
{
\treturn this.templates[name];
};

/**
 * Function: createGraph
 *
 * Creates the <graph> for the editor. The graph is created with no
 * container and is initialized from <setGraphContainer>.
 */
mxEditor.prototype.createGraph = function ()
{
\tvar graph = new mxGraph(null, null, this.graphRenderHint);

\t// Enables rubberband, tooltips, panning
\tgraph.setTooltips(true);
\tgraph.setPanning(true);

\t// Overrides the dblclick method on the graph to
\t// invoke the dblClickAction for a cell and reset
\t// the selection tool in the toolbar
\tthis.installDblClickHandler(graph);

\t// Installs the command history
\tthis.installUndoHandler(graph);

\t// Installs the handlers for the root event
\tthis.installDrillHandler(graph);

\t// Installs the handler for validation
\tthis.installChangeHandler(graph);

\t// Installs the handler for calling the
\t// insert function and consume the
\t// event if an insert function is defined
\tthis.installInsertHandler(graph);

\t// Redirects the function for creating the
\t// popupmenu items
\tgraph.popupMenuHandler.factoryMethod =
\t\tmxUtils.bind(this, function(menu, cell, evt)
\t\t{
\t\t\treturn this.createPopupMenu(menu, cell, evt);
\t\t});

\t// Redirects the function for creating
\t// new connections in the diagram
\tgraph.connectionHandler.factoryMethod =
\t\tmxUtils.bind(this, function(source, target)
\t\t{
\t\t\treturn this.createEdge(source, target);
\t\t});

\t// Maintains swimlanes and installs autolayout
\tthis.createSwimlaneManager(graph);
\tthis.createLayoutManager(graph);

\treturn graph;
};

/**
 * Function: createSwimlaneManager
 *
 * Sets the graph's container using <mxGraph.init>.
 */
mxEditor.prototype.createSwimlaneManager = function (graph)
{
\tvar swimlaneMgr = new mxSwimlaneManager(graph, false);

\tswimlaneMgr.isHorizontal = mxUtils.bind(this, function()
\t{
\t\treturn this.horizontalFlow;
\t});

\tswimlaneMgr.isEnabled = mxUtils.bind(this, function()
\t{
\t\treturn this.maintainSwimlanes;
\t});

\treturn swimlaneMgr;
};

/**
 * Function: createLayoutManager
 *
 * Creates a layout manager for the swimlane and diagram layouts, that
 * is, the locally defined inter- and intraswimlane layouts.
 */
mxEditor.prototype.createLayoutManager = function (graph)
{
\tvar layoutMgr = new mxLayoutManager(graph);

\tvar self = this; // closure
\tlayoutMgr.getLayout = function(cell)
\t{
\t\tvar layout = null;
\t\tvar model = self.graph.getModel();

\t\tif (model.getParent(cell) != null)
\t\t{
\t\t\t// Executes the swimlane layout if a child of
\t\t\t// a swimlane has been changed. The layout is
\t\t\t// lazy created in createSwimlaneLayout.
\t\t\tif (self.layoutSwimlanes &&
\t\t\t\tgraph.isSwimlane(cell))
\t\t\t{
\t\t\t\tif (self.swimlaneLayout == null)
\t\t\t\t{
\t\t\t\t\tself.swimlaneLayout = self.createSwimlaneLayout();
\t\t\t\t}

\t\t\t\tlayout = self.swimlaneLayout;
\t\t\t}

\t\t\t// Executes the diagram layout if the modified
\t\t\t// cell is a top-level cell. The layout is
\t\t\t// lazy created in createDiagramLayout.
\t\t\telse if (self.layoutDiagram &&
\t\t\t\t(graph.isValidRoot(cell) ||
\t\t\t\tmodel.getParent(model.getParent(cell)) == null))
\t\t\t{
\t\t\t\tif (self.diagramLayout == null)
\t\t\t\t{
\t\t\t\t\tself.diagramLayout = self.createDiagramLayout();
\t\t\t\t}

\t\t\t\tlayout = self.diagramLayout;
\t\t\t}
\t\t}

\t\treturn layout;
\t};

\treturn layoutMgr;
};

/**
 * Function: setGraphContainer
 *
 * Sets the graph's container using <mxGraph.init>.
 */
mxEditor.prototype.setGraphContainer = function (container)
{
\tif (this.graph.container == null)
\t{
\t\t// Creates the graph instance inside the given container and render hint
\t\t//this.graph = new mxGraph(container, null, this.graphRenderHint);
\t\tthis.graph.init(container);

\t\t// Install rubberband selection as the last
\t\t// action handler in the chain
\t\tthis.rubberband = new mxRubberband(this.graph);

\t\t// Disables the context menu
\t\tif (this.disableContextMenu)
\t\t{
\t\t\tmxEvent.disableContextMenu(container);
\t\t}

\t\t// Workaround for stylesheet directives in IE
\t\tif (mxClient.IS_QUIRKS)
\t\t{
\t\t\tnew mxDivResizer(container);
\t\t}
\t}
};

/**
 * Function: installDblClickHandler
 *
 * Overrides <mxGraph.dblClick> to invoke <dblClickAction>
 * on a cell and reset the selection tool in the toolbar.
 */
mxEditor.prototype.installDblClickHandler = function (graph)
{
\t// Installs a listener for double click events
\tgraph.addListener(mxEvent.DOUBLE_CLICK,
\t\tmxUtils.bind(this, function(sender, evt)
\t\t{
\t\t\tvar cell = evt.getProperty('cell');

\t\t\tif (cell != null &&
\t\t\t\tgraph.isEnabled() &&
\t\t\t\tthis.dblClickAction != null)
\t\t\t{
\t\t\t\tthis.execute(this.dblClickAction, cell);
\t\t\t\tevt.consume();
\t\t\t}
\t\t})
\t);
};

/**
 * Function: installUndoHandler
 *
 * Adds the <undoManager> to the graph model and the view.
 */
mxEditor.prototype.installUndoHandler = function (graph)
{
\tvar listener = mxUtils.bind(this, function(sender, evt)
\t{
\t\tvar edit = evt.getProperty('edit');
\t\tthis.undoManager.undoableEditHappened(edit);
\t});

\tgraph.getModel().addListener(mxEvent.UNDO, listener);
\tgraph.getView().addListener(mxEvent.UNDO, listener);

\t// Keeps the selection state in sync
\tvar undoHandler = function(sender, evt)
\t{
\t\tvar changes = evt.getProperty('edit').changes;
\t\tgraph.setSelectionCells(graph.getSelectionCellsForChanges(changes));
\t};

\tthis.undoManager.addListener(mxEvent.UNDO, undoHandler);
\tthis.undoManager.addListener(mxEvent.REDO, undoHandler);
};

/**
 * Function: installDrillHandler
 *
 * Installs listeners for dispatching the <root> event.
 */
mxEditor.prototype.installDrillHandler = function (graph)
{
\tvar listener = mxUtils.bind(this, function(sender)
\t{
\t\tthis.fireEvent(new mxEventObject(mxEvent.ROOT));
\t});

\tgraph.getView().addListener(mxEvent.DOWN, listener);
\tgraph.getView().addListener(mxEvent.UP, listener);
};

/**
 * Function: installChangeHandler
 *
 * Installs the listeners required to automatically validate
 * the graph. On each change of the root, this implementation
 * fires a <root> event.
 */
mxEditor.prototype.installChangeHandler = function (graph)
{
\tvar listener = mxUtils.bind(this, function(sender, evt)
\t{
\t\t// Updates the modified state
\t\tthis.setModified(true);

\t\t// Automatically validates the graph
\t\t// after each change
\t\tif (this.validating == true)
\t\t{
\t\t\tgraph.validateGraph();
\t\t}

\t\t// Checks if the root has been changed
\t\tvar changes = evt.getProperty('edit').changes;

\t\tfor (var i = 0; i < changes.length; i++)
\t\t{
\t\t\tvar change = changes[i];

\t\t\tif (change instanceof mxRootChange ||
\t\t\t\t(change instanceof mxValueChange &&
\t\t\t\tchange.cell == this.graph.model.root) ||
\t\t\t\t(change instanceof mxCellAttributeChange &&
\t\t\t\tchange.cell == this.graph.model.root))
\t\t\t{
\t\t\t\tthis.fireEvent(new mxEventObject(mxEvent.ROOT));
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t});

\tgraph.getModel().addListener(mxEvent.CHANGE, listener);
};

/**
 * Function: installInsertHandler
 *
 * Installs the handler for invoking <insertFunction> if
 * one is defined.
 */
mxEditor.prototype.installInsertHandler = function (graph)
{
\tvar self = this; // closure
\tvar insertHandler =
\t{
\t\tmouseDown: function(sender, me)
\t\t{
\t\t\tif (self.insertFunction != null &&
\t\t\t\t!me.isPopupTrigger() &&
\t\t\t\t(self.forcedInserting ||
\t\t\t\tme.getState() == null))
\t\t\t{
\t\t\t\tself.graph.clearSelection();
\t\t\t\tself.insertFunction(me.getEvent(), me.getCell());

\t\t\t\t// Consumes the rest of the events
\t\t\t\t// for this gesture (down, move, up)
\t\t\t\tthis.isActive = true;
\t\t\t\tme.consume();
\t\t\t}
\t\t},

\t\tmouseMove: function(sender, me)
\t\t{
\t\t\tif (this.isActive)
\t\t\t{
\t\t\t\tme.consume();
\t\t\t}
\t\t},

\t\tmouseUp: function(sender, me)
\t\t{
\t\t\tif (this.isActive)
\t\t\t{
\t\t\t\tthis.isActive = false;
\t\t\t\tme.consume();
\t\t\t}
\t\t}
\t};

\tgraph.addMouseListener(insertHandler);
};

/**
 * Function: createDiagramLayout
 *
 * Creates the layout instance used to layout the
 * swimlanes in the diagram.
 */
mxEditor.prototype.createDiagramLayout = function ()
{
\tvar gs = this.graph.gridSize;
\tvar layout = new mxStackLayout(this.graph, !this.horizontalFlow,
\t\t this.swimlaneSpacing, 2*gs, 2*gs);

\t// Overrides isIgnored to only take into account swimlanes
\tlayout.isVertexIgnored = function(cell)
\t{
\t\treturn !layout.graph.isSwimlane(cell);
\t};

\treturn layout;
};

/**
 * Function: createSwimlaneLayout
 *
 * Creates the layout instance used to layout the
 * children of each swimlane.
 */
mxEditor.prototype.createSwimlaneLayout = function ()
{
\treturn new mxCompactTreeLayout(this.graph, this.horizontalFlow);
};

/**
 * Function: createToolbar
 *
 * Creates the <toolbar> with no container.
 */
mxEditor.prototype.createToolbar = function ()
{
\treturn new mxDefaultToolbar(null, this);
};

/**
 * Function: setToolbarContainer
 *
 * Initializes the toolbar for the given container.
 */
mxEditor.prototype.setToolbarContainer = function (container)
{
\tthis.toolbar.init(container);

\t// Workaround for stylesheet directives in IE
\tif (mxClient.IS_QUIRKS)
\t{
\t\tnew mxDivResizer(container);
\t}
};

/**
 * Function: setStatusContainer
 *
 * Creates the <status> using the specified container.
 *
 * This implementation adds listeners in the editor to
 * display the last saved time and the current filename
 * in the status bar.
 *
 * Parameters:
 *
 * container - DOM node that will contain the statusbar.
 */
mxEditor.prototype.setStatusContainer = function (container)
{
\tif (this.status == null)
\t{
\t\tthis.status = container;

\t\t// Prints the last saved time in the status bar
\t\t// when files are saved
\t\tthis.addListener(mxEvent.SAVE, mxUtils.bind(this, function()
\t\t{
\t\t\tvar tstamp = new Date().toLocaleString();
\t\t\tthis.setStatus((mxResources.get(this.lastSavedResource) ||
\t\t\t\tthis.lastSavedResource)+': '+tstamp);
\t\t}));

\t\t// Updates the statusbar to display the filename
\t\t// when new files are opened
\t\tthis.addListener(mxEvent.OPEN, mxUtils.bind(this, function()
\t\t{
\t\t\tthis.setStatus((mxResources.get(this.currentFileResource) ||
\t\t\t\tthis.currentFileResource)+': '+this.filename);
\t\t}));

\t\t// Workaround for stylesheet directives in IE
\t\tif (mxClient.IS_QUIRKS)
\t\t{
\t\t\tnew mxDivResizer(container);
\t\t}
\t}
};

/**
 * Function: setStatus
 *
 * Display the specified message in the status bar.
 *
 * Parameters:
 *
 * message - String the specified the message to
 * be displayed.
 */
mxEditor.prototype.setStatus = function (message)
{
\tif (this.status != null && message != null)
\t{
\t\tthis.status.innerHTML = message;
\t}
};

/**
 * Function: setTitleContainer
 *
 * Creates a listener to update the inner HTML of the
 * specified DOM node with the value of <getTitle>.
 *
 * Parameters:
 *
 * container - DOM node that will contain the title.
 */
mxEditor.prototype.setTitleContainer = function (container)
{
\tthis.addListener(mxEvent.ROOT, mxUtils.bind(this, function(sender)
\t{
\t\tcontainer.innerHTML = this.getTitle();
\t}));

\t// Workaround for stylesheet directives in IE
\tif (mxClient.IS_QUIRKS)
\t{
\t\tnew mxDivResizer(container);
\t}
};

/**
 * Function: treeLayout
 *
 * Executes a vertical or horizontal compact tree layout
 * using the specified cell as an argument. The cell may
 * either be a group or the root of a tree.
 *
 * Parameters:
 *
 * cell - <mxCell> to use in the compact tree layout.
 * horizontal - Optional boolean to specify the tree's
 * orientation. Default is true.
 */
mxEditor.prototype.treeLayout = function (cell, horizontal)
{
\tif (cell != null)
\t{
\t\tvar layout = new mxCompactTreeLayout(this.graph, horizontal);
\t\tlayout.execute(cell);
\t}
};

/**
 * Function: getTitle
 *
 * Returns the string value for the current root of the
 * diagram.
 */
mxEditor.prototype.getTitle = function ()
{
\tvar title = '';
\tvar graph = this.graph;
\tvar cell = graph.getCurrentRoot();

\twhile (cell != null &&
\t\t   graph.getModel().getParent(
\t\t\t\tgraph.getModel().getParent(cell)) != null)
\t{
\t\t// Append each label of a valid root
\t\tif (graph.isValidRoot(cell))
\t\t{
\t\t\ttitle = ' > ' +
\t\t\tgraph.convertValueToString(cell) + title;
\t\t}

\t\tcell = graph.getModel().getParent(cell);
\t}

\tvar prefix = this.getRootTitle();

\treturn prefix + title;
};

/**
 * Function: getRootTitle
 *
 * Returns the string value of the root cell in
 * <mxGraph.model>.
 */
mxEditor.prototype.getRootTitle = function ()
{
\tvar root = this.graph.getModel().getRoot();
\treturn this.graph.convertValueToString(root);
};

/**
 * Function: undo
 *
 * Undo the last change in <graph>.
 */
mxEditor.prototype.undo = function ()
{
\tthis.undoManager.undo();
};

/**
 * Function: redo
 *
 * Redo the last change in <graph>.
 */
mxEditor.prototype.redo = function ()
{
\tthis.undoManager.redo();
};

/**
 * Function: groupCells
 *
 * Invokes <createGroup> to create a new group cell and the invokes
 * <mxGraph.groupCells>, using the grid size of the graph as the spacing
 * in the group's content area.
 */
mxEditor.prototype.groupCells = function ()
{
\tvar border = (this.groupBorderSize != null) ?
\t\tthis.groupBorderSize :
\t\tthis.graph.gridSize;
\treturn this.graph.groupCells(this.createGroup(), border);
};

/**
 * Function: createGroup
 *
 * Creates and returns a clone of <defaultGroup> to be used
 * as a new group cell in <group>.
 */
mxEditor.prototype.createGroup = function ()
{
\tvar model = this.graph.getModel();

\treturn model.cloneCell(this.defaultGroup);
};

/**
 * Function: open
 *
 * Opens the specified file synchronously and parses it using
 * <readGraphModel>. It updates <filename> and fires an <open>-event after
 * the file has been opened. Exceptions should be handled as follows:
 *
 * (code)
 * try
 * {
 *   editor.open(filename);
 * }
 * catch (e)
 * {
 *   mxUtils.error('Cannot open ' + filename +
 *     ': ' + e.message, 280, true);
 * }
 * (end)
 *
 * Parameters:
 *
 * filename - URL of the file to be opened.
 */
mxEditor.prototype.open = function (filename)
{
\tif (filename != null)
\t{
\t\tvar xml = mxUtils.load(filename).getXml();
\t\tthis.readGraphModel(xml.documentElement);
\t\tthis.filename = filename;

\t\tthis.fireEvent(new mxEventObject(mxEvent.OPEN, 'filename', filename));
\t}
};

/**
 * Function: readGraphModel
 *
 * Reads the specified XML node into the existing graph model and resets
 * the command history and modified state.
 */
mxEditor.prototype.readGraphModel = function (node)
{
\tvar dec = new mxCodec(node.ownerDocument);
\tdec.decode(node, this.graph.getModel());
\tthis.resetHistory();
};

/**
 * Function: save
 *
 * Posts the string returned by <writeGraphModel> to the given URL or the
 * URL returned by <getUrlPost>. The actual posting is carried out by
 * <postDiagram>. If the URL is null then the resulting XML will be
 * displayed using <mxUtils.popup>. Exceptions should be handled as
 * follows:
 *
 * (code)
 * try
 * {
 *   editor.save();
 * }
 * catch (e)
 * {
 *   mxUtils.error('Cannot save : ' + e.message, 280, true);
 * }
 * (end)
 */
mxEditor.prototype.save = function (url, linefeed)
{
\t// Gets the URL to post the data to
\turl = url || this.getUrlPost();

\t// Posts the data if the URL is not empty
\tif (url != null && url.length > 0)
\t{
\t\tvar data = this.writeGraphModel(linefeed);
\t\tthis.postDiagram(url, data);

\t\t// Resets the modified flag
\t\tthis.setModified(false);
\t}

\t// Dispatches a save event
\tthis.fireEvent(new mxEventObject(mxEvent.SAVE, 'url', url));
};

/**
 * Function: postDiagram
 *
 * Hook for subclassers to override the posting of a diagram
 * represented by the given node to the given URL. This fires
 * an asynchronous <post> event if the diagram has been posted.
 *
 * Example:
 *
 * To replace the diagram with the diagram in the response, use the
 * following code.
 *
 * (code)
 * editor.addListener(mxEvent.POST, function(sender, evt)
 * {
 *   // Process response (replace diagram)
 *   var req = evt.getProperty('request');
 *   var root = req.getDocumentElement();
 *   editor.graph.readGraphModel(root)
 * });
 * (end)
 */
mxEditor.prototype.postDiagram = function (url, data)
{
\tif (this.escapePostData)
\t{
\t\tdata = encodeURIComponent(data);
\t}

\tmxUtils.post(url, this.postParameterName+'='+data,
\t\tmxUtils.bind(this, function(req)
\t\t{
\t\t\tthis.fireEvent(new mxEventObject(mxEvent.POST,
\t\t\t\t'request', req, 'url', url, 'data', data));
\t\t})
\t);
};

/**
 * Function: writeGraphModel
 *
 * Hook to create the string representation of the diagram. The default
 * implementation uses an <mxCodec> to encode the graph model as
 * follows:
 *
 * (code)
 * var enc = new mxCodec();
 * var node = enc.encode(this.graph.getModel());
 * return mxUtils.getXml(node, this.linefeed);
 * (end)
 *
 * Parameters:
 *
 * linefeed - Optional character to be used as the linefeed. Default is
 * <linefeed>.
 */
mxEditor.prototype.writeGraphModel = function (linefeed)
{
\tlinefeed = (linefeed != null) ? linefeed : this.linefeed;
\tvar enc = new mxCodec();
\tvar node = enc.encode(this.graph.getModel());

\treturn mxUtils.getXml(node, linefeed);
};

/**
 * Function: getUrlPost
 *
 * Returns the URL to post the diagram to. This is used
 * in <save>. The default implementation returns <urlPost>,
 * adding <code>?draft=true</code>.
 */
mxEditor.prototype.getUrlPost = function ()
{
\treturn this.urlPost;
};

/**
 * Function: getUrlImage
 *
 * Returns the URL to create the image with. This is typically
 * the URL of a backend which accepts an XML representation
 * of a graph view to create an image. The function is used
 * in the image action to create an image. This implementation
 * returns <urlImage>.
 */
mxEditor.prototype.getUrlImage = function ()
{
\treturn this.urlImage;
};

/**
 * Function: swapStyles
 *
 * Swaps the styles for the given names in the graph's
 * stylesheet and refreshes the graph.
 */
mxEditor.prototype.swapStyles = function (first, second)
{
\tvar style = this.graph.getStylesheet().styles[second];
\tthis.graph.getView().getStylesheet().putCellStyle(
\t\tsecond, this.graph.getStylesheet().styles[first]);
\tthis.graph.getStylesheet().putCellStyle(first, style);
\tthis.graph.refresh();
};

/**
 * Function: showProperties
 *
 * Creates and shows the properties dialog for the given
 * cell. The content area of the dialog is created using
 * <createProperties>.
 */
mxEditor.prototype.showProperties = function (cell)
{
\tcell = cell || this.graph.getSelectionCell();

\t// Uses the root node for the properties dialog
\t// if not cell was passed in and no cell is
\t// selected
\tif (cell == null)
\t{
\t\tcell = this.graph.getCurrentRoot();

\t\tif (cell == null)
\t\t{
\t\t\tcell = this.graph.getModel().getRoot();
\t\t}
\t}

\tif (cell != null)
\t{
\t\t// Makes sure there is no in-place editor in the
\t\t// graph and computes the location of the dialog
\t\tthis.graph.stopEditing(true);

\t\tvar offset = mxUtils.getOffset(this.graph.container);
\t\tvar x = offset.x+10;
\t\tvar y = offset.y;

\t\t// Avoids moving the dialog if it is alredy open
\t\tif (this.properties != null && !this.movePropertiesDialog)
\t\t{
\t\t\tx = this.properties.getX();
\t\t\ty = this.properties.getY();
\t\t}

\t\t// Places the dialog near the cell for which it
\t\t// displays the properties
\t\telse
\t\t{
\t\t\tvar bounds = this.graph.getCellBounds(cell);

\t\t\tif (bounds != null)
\t\t\t{
\t\t\t\tx += bounds.x+Math.min(200, bounds.width);
\t\t\t\ty += bounds.y;
\t\t\t}
\t\t}

\t\t// Hides the existing properties dialog and creates a new one with the
\t\t// contents created in the hook method
\t\tthis.hideProperties();
\t\tvar node = this.createProperties(cell);

\t\tif (node != null)
\t\t{
\t\t\t// Displays the contents in a window and stores a reference to the
\t\t\t// window for later hiding of the window
\t\t\tthis.properties = new mxWindow(mxResources.get(this.propertiesResource) ||
\t\t\t\tthis.propertiesResource, node, x, y, this.propertiesWidth, this.propertiesHeight, false);
\t\t\tthis.properties.setVisible(true);
\t\t}
\t}
};

/**
 * Function: isPropertiesVisible
 *
 * Returns true if the properties dialog is currently visible.
 */
mxEditor.prototype.isPropertiesVisible = function ()
{
\treturn this.properties != null;
};

/**
 * Function: createProperties
 *
 * Creates and returns the DOM node that represents the contents
 * of the properties dialog for the given cell. This implementation
 * works for user objects that are XML nodes and display all the
 * node attributes in a form.
 */
mxEditor.prototype.createProperties = function (cell)
{
\tvar model = this.graph.getModel();
\tvar value = model.getValue(cell);

\tif (mxUtils.isNode(value))
\t{
\t\t// Creates a form for the user object inside
\t\t// the cell
\t\tvar form = new mxForm('properties');

\t\t// Adds a readonly field for the cell id
\t\tvar id = form.addText('ID', cell.getId());
\t\tid.setAttribute('readonly', 'true');

\t\tvar geo = null;
\t\tvar yField = null;
\t\tvar xField = null;
\t\tvar widthField = null;
\t\tvar heightField = null;

\t\t// Adds fields for the location and size
\t\tif (model.isVertex(cell))
\t\t{
\t\t\tgeo = model.getGeometry(cell);

\t\t\tif (geo != null)
\t\t\t{
\t\t\t\tyField = form.addText('top', geo.y);
\t\t\t\txField = form.addText('left', geo.x);
\t\t\t\twidthField = form.addText('width', geo.width);
\t\t\t\theightField = form.addText('height', geo.height);
\t\t\t}
\t\t}

\t\t// Adds a field for the cell style
\t\tvar tmp = model.getStyle(cell);
\t\tvar style = form.addText('Style', tmp || '');

\t\t// Creates textareas for each attribute of the
\t\t// user object within the cell
\t\tvar attrs = value.attributes;
\t\tvar texts = [];

\t\tfor (var i = 0; i < attrs.length; i++)
\t\t{
\t\t\t// Creates a textarea with more lines for
\t\t\t// the cell label
\t\t\tvar val = attrs[i].value;
\t\t\ttexts[i] = form.addTextarea(attrs[i].nodeName, val,
\t\t\t\t(attrs[i].nodeName == 'label') ? 4 : 2);
\t\t}

\t\t// Adds an OK and Cancel button to the dialog
\t\t// contents and implements the respective
\t\t// actions below

\t\t// Defines the function to be executed when the
\t\t// OK button is pressed in the dialog
\t\tvar okFunction = mxUtils.bind(this, function()
\t\t{
\t\t\t// Hides the dialog
\t\t\tthis.hideProperties();

\t\t\t// Supports undo for the changes on the underlying
\t\t\t// XML structure / XML node attribute changes.
\t\t\tmodel.beginUpdate();
\t\t\ttry
\t\t\t{
\t\t\t\tif (geo != null)
\t\t\t\t{
\t\t\t\t\tgeo = geo.clone();

\t\t\t\t\tgeo.x = parseFloat(xField.value);
\t\t\t\t\tgeo.y = parseFloat(yField.value);
\t\t\t\t\tgeo.width = parseFloat(widthField.value);
\t\t\t\t\tgeo.height = parseFloat(heightField.value);

\t\t\t\t\tmodel.setGeometry(cell, geo);
\t\t\t\t}

\t\t\t\t// Applies the style
\t\t\t\tif (style.value.length > 0)
\t\t\t\t{
\t\t\t\t\tmodel.setStyle(cell, style.value);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tmodel.setStyle(cell, null);
\t\t\t\t}

\t\t\t\t// Creates an undoable change for each
\t\t\t\t// attribute and executes it using the
\t\t\t\t// model, which will also make the change
\t\t\t\t// part of the current transaction
\t\t\t\tfor (var i=0; i<attrs.length; i++)
\t\t\t\t{
\t\t\t\t\tvar edit = new mxCellAttributeChange(
\t\t\t\t\t\tcell, attrs[i].nodeName,
\t\t\t\t\t\ttexts[i].value);
\t\t\t\t\tmodel.execute(edit);
\t\t\t\t}

\t\t\t\t// Checks if the graph wants cells to
\t\t\t\t// be automatically sized and updates
\t\t\t\t// the size as an undoable step if
\t\t\t\t// the feature is enabled
\t\t\t\tif (this.graph.isAutoSizeCell(cell))
\t\t\t\t{
\t\t\t\t\tthis.graph.updateCellSize(cell);
\t\t\t\t}
\t\t\t}
\t\t\tfinally
\t\t\t{
\t\t\t\tmodel.endUpdate();
\t\t\t}
\t\t});

\t\t// Defines the function to be executed when the
\t\t// Cancel button is pressed in the dialog
\t\tvar cancelFunction = mxUtils.bind(this, function()
\t\t{
\t\t\t// Hides the dialog
\t\t\tthis.hideProperties();
\t\t});

\t\tform.addButtons(okFunction, cancelFunction);

\t\treturn form.table;
\t}

\treturn null;
};

/**
 * Function: hideProperties
 *
 * Hides the properties dialog.
 */
mxEditor.prototype.hideProperties = function ()
{
\tif (this.properties != null)
\t{
\t\tthis.properties.destroy();
\t\tthis.properties = null;
\t}
};

/**
 * Function: showTasks
 *
 * Shows the tasks window. The tasks window is created using <createTasks>. The
 * default width of the window is 200 pixels, the y-coordinate of the location
 * can be specifies in <tasksTop> and the x-coordinate is right aligned with a
 * 20 pixel offset from the right border. To change the location of the tasks
 * window, the following code can be used:
 *
 * (code)
 * var oldShowTasks = mxEditor.prototype.showTasks;
 * mxEditor.prototype.showTasks = function()
 * {
 *   oldShowTasks.apply(this, arguments); // \"supercall\"
 *
 *   if (this.tasks != null)
 *   {
 *     this.tasks.setLocation(10, 10);
 *   }
 * };
 * (end)
 */
mxEditor.prototype.showTasks = function ()
{
\tif (this.tasks == null)
\t{
\t\tvar div = document.createElement('div');
\t\tdiv.style.padding = '4px';
\t\tdiv.style.paddingLeft = '20px';
\t\tvar w = document.body.clientWidth;
\t\tvar wnd = new mxWindow(
\t\t\tmxResources.get(this.tasksResource) ||
\t\t\tthis.tasksResource,
\t\t\tdiv, w - 220, this.tasksTop, 200);
\t\twnd.setClosable(true);
\t\twnd.destroyOnClose = false;

\t\t// Installs a function to update the contents
\t\t// of the tasks window on every change of the
\t\t// model, selection or root.
\t\tvar funct = mxUtils.bind(this, function(sender)
\t\t{
\t\t\tmxEvent.release(div);
\t\t\tdiv.innerHTML = '';
\t\t\tthis.createTasks(div);
\t\t});

\t\tthis.graph.getModel().addListener(mxEvent.CHANGE, funct);
\t\tthis.graph.getSelectionModel().addListener(mxEvent.CHANGE, funct);
\t\tthis.graph.addListener(mxEvent.ROOT, funct);

\t\t// Assigns the icon to the tasks window
\t\tif (this.tasksWindowImage != null)
\t\t{
\t\t\twnd.setImage(this.tasksWindowImage);
\t\t}

\t\tthis.tasks = wnd;
\t\tthis.createTasks(div);
\t}

\tthis.tasks.setVisible(true);
};

/**
 * Function: refreshTasks
 *
 * Updates the contents of the tasks window using <createTasks>.
 */
mxEditor.prototype.refreshTasks = function (div)
{
\tif (this.tasks != null)
\t{
\t\tvar div = this.tasks.content;
\t\tmxEvent.release(div);
\t\tdiv.innerHTML = '';
\t\tthis.createTasks(div);
\t}
};

/**
 * Function: createTasks
 *
 * Updates the contents of the given DOM node to
 * display the tasks associated with the current
 * editor state. This is invoked whenever there
 * is a possible change of state in the editor.
 * Default implementation is empty.
 */
mxEditor.prototype.createTasks = function (div)
{
\t// override
};

/**
 * Function: showHelp
 *
 * Shows the help window. If the help window does not exist
 * then it is created using an iframe pointing to the resource
 * for the <code>urlHelp</code> key or <urlHelp> if the resource
 * is undefined.
 */
mxEditor.prototype.showHelp = function (tasks)
{
\tif (this.help == null)
\t{
\t\tvar frame = document.createElement('iframe');
\t\tframe.setAttribute('src', mxResources.get('urlHelp') || this.urlHelp);
\t\tframe.setAttribute('height', '100%');
\t\tframe.setAttribute('width', '100%');
\t\tframe.setAttribute('frameBorder', '0');
\t\tframe.style.backgroundColor = 'white';

\t\tvar w = document.body.clientWidth;
\t\tvar h = (document.body.clientHeight || document.documentElement.clientHeight);

\t\tvar wnd = new mxWindow(mxResources.get(this.helpResource) || this.helpResource,
\t\t\tframe, (w-this.helpWidth)/2, (h-this.helpHeight)/3, this.helpWidth, this.helpHeight);
\t\twnd.setMaximizable(true);
\t\twnd.setClosable(true);
\t\twnd.destroyOnClose = false;
\t\twnd.setResizable(true);

\t\t// Assigns the icon to the help window
\t\tif (this.helpWindowImage != null)
\t\t{
\t\t\twnd.setImage(this.helpWindowImage);
\t\t}

\t\t// Workaround for ignored iframe height 100% in FF
\t\tif (mxClient.IS_NS)
\t\t{
\t\t\tvar handler = function(sender)
\t\t\t{
\t\t\t\tvar h = wnd.div.offsetHeight;
\t\t\t\tframe.setAttribute('height', (h-26)+'px');
\t\t\t};

\t\t\twnd.addListener(mxEvent.RESIZE_END, handler);
\t\t\twnd.addListener(mxEvent.MAXIMIZE, handler);
\t\t\twnd.addListener(mxEvent.NORMALIZE, handler);
\t\t\twnd.addListener(mxEvent.SHOW, handler);
\t\t}

\t\tthis.help = wnd;
\t}

\tthis.help.setVisible(true);
};

/**
 * Function: showOutline
 *
 * Shows the outline window. If the window does not exist, then it is
 * created using an <mxOutline>.
 */
mxEditor.prototype.showOutline = function ()
{
\tvar create = this.outline == null;

\tif (create)
\t{
\t\tvar div = document.createElement('div');

\t\tdiv.style.overflow = 'hidden';
\t\tdiv.style.position = 'relative';
\t\tdiv.style.width = '100%';
\t\tdiv.style.height = '100%';
\t\tdiv.style.background = 'white';
\t\tdiv.style.cursor = 'move';

\t\tif (document.documentMode == 8)
\t\t{
\t\t\tdiv.style.filter = 'progid:DXImageTransform.Microsoft.alpha(opacity=100)';
\t\t}

\t\tvar wnd = new mxWindow(
\t\t\tmxResources.get(this.outlineResource) ||
\t\t\tthis.outlineResource,
\t\t\tdiv, 600, 480, 200, 200, false);

\t\t// Creates the outline in the specified div
\t\t// and links it to the existing graph
\t\tvar outline = new mxOutline(this.graph, div);
\t\twnd.setClosable(true);
\t\twnd.setResizable(true);
\t\twnd.destroyOnClose = false;

\t\twnd.addListener(mxEvent.RESIZE_END, function()
\t\t{
\t\t\toutline.update();
\t\t});

\t\tthis.outline = wnd;
\t\tthis.outline.outline = outline;
\t}

\t// Finally shows the outline
\tthis.outline.setVisible(true);
\tthis.outline.outline.update(true);
};

/**
 * Function: setMode
 *
 * Puts the graph into the specified mode. The following modenames are
 * supported:
 *
 * select - Selects using the left mouse button, new connections
 * are disabled.
 * connect - Selects using the left mouse button or creates new
 * connections if mouse over cell hotspot. See <mxConnectionHandler>.
 * pan - Pans using the left mouse button, new connections are disabled.
 */
mxEditor.prototype.setMode = function(modename)
{
\tif (modename == 'select')
\t{
\t\tthis.graph.panningHandler.useLeftButtonForPanning = false;
\t\tthis.graph.setConnectable(false);
\t}
\telse if (modename == 'connect')
\t{
\t\tthis.graph.panningHandler.useLeftButtonForPanning = false;
\t\tthis.graph.setConnectable(true);
\t}
\telse if (modename == 'pan')
\t{
\t\tthis.graph.panningHandler.useLeftButtonForPanning = true;
\t\tthis.graph.setConnectable(false);
\t}
};

/**
 * Function: createPopupMenu
 *
 * Uses <popupHandler> to create the menu in the graph's
 * panning handler. The redirection is setup in
 * <setToolbarContainer>.
 */
mxEditor.prototype.createPopupMenu = function (menu, cell, evt)
{
\tthis.popupHandler.createMenu(this, menu, cell, evt);
};

/**
 * Function: createEdge
 *
 * Uses <defaultEdge> as the prototype for creating new edges
 * in the connection handler of the graph. The style of the
 * edge will be overridden with the value returned by
 * <getEdgeStyle>.
 */
mxEditor.prototype.createEdge = function (source, target)
{
\t// Clones the defaultedge prototype
\tvar e = null;

\tif (this.defaultEdge != null)
\t{
\t\tvar model = this.graph.getModel();
\t\te = model.cloneCell(this.defaultEdge);
\t}
\telse
\t{
\t\te = new mxCell('');
\t\te.setEdge(true);

\t\tvar geo = new mxGeometry();
\t\tgeo.relative = true;
\t\te.setGeometry(geo);
\t}

\t// Overrides the edge style
\tvar style = this.getEdgeStyle();

\tif (style != null)
\t{
\t\te.setStyle(style);
\t}

\treturn e;
};

/**
 * Function: getEdgeStyle
 *
 * Returns a string identifying the style of new edges.
 * The function is used in <createEdge> when new edges
 * are created in the graph.
 */
mxEditor.prototype.getEdgeStyle = function ()
{
\treturn this.defaultEdgeStyle;
};

/**
 * Function: consumeCycleAttribute
 *
 * Returns the next attribute in <cycleAttributeValues>
 * or null, if not attribute should be used in the
 * specified cell.
 */
mxEditor.prototype.consumeCycleAttribute = function (cell)
{
\treturn (this.cycleAttributeValues != null &&
\t\tthis.cycleAttributeValues.length > 0 &&
\t\tthis.graph.isSwimlane(cell)) ?
\t\tthis.cycleAttributeValues[this.cycleAttributeIndex++ %
\t\t\tthis.cycleAttributeValues.length] : null;
};

/**
 * Function: cycleAttribute
 *
 * Uses the returned value from <consumeCycleAttribute>
 * as the value for the <cycleAttributeName> key in
 * the given cell's style.
 */
mxEditor.prototype.cycleAttribute = function (cell)
{
\tif (this.cycleAttributeName != null)
\t{
\t\tvar value = this.consumeCycleAttribute(cell);

\t\tif (value != null)
\t\t{
\t\t\tcell.setStyle(cell.getStyle()+';'+
\t\t\t\tthis.cycleAttributeName+'='+value);
\t\t}
\t}
};

/**
 * Function: addVertex
 *
 * Adds the given vertex as a child of parent at the specified
 * x and y coordinate and fires an <addVertex> event.
 */
mxEditor.prototype.addVertex = function (parent, vertex, x, y)
{
\tvar model = this.graph.getModel();

\twhile (parent != null && !this.graph.isValidDropTarget(parent))
\t{
\t\tparent = model.getParent(parent);
\t}

\tparent = (parent != null) ? parent : this.graph.getSwimlaneAt(x, y);
\tvar scale = this.graph.getView().scale;

\tvar geo = model.getGeometry(vertex);
\tvar pgeo = model.getGeometry(parent);

\tif (this.graph.isSwimlane(vertex) &&
\t\t!this.graph.swimlaneNesting)
\t{
\t\tparent = null;
\t}
\telse if (parent == null && this.swimlaneRequired)
\t{
\t\treturn null;
\t}
\telse if (parent != null && pgeo != null)
\t{
\t\t// Keeps vertex inside parent
\t\tvar state = this.graph.getView().getState(parent);

\t\tif (state != null)
\t\t{
\t\t\tx -= state.origin.x * scale;
\t\t\ty -= state.origin.y * scale;

\t\t\tif (this.graph.isConstrainedMoving)
\t\t\t{
\t\t\t\tvar width = geo.width;
\t\t\t\tvar height = geo.height;
\t\t\t\tvar tmp = state.x+state.width;

\t\t\t\tif (x+width > tmp)
\t\t\t\t{
\t\t\t\t\tx -= x+width - tmp;
\t\t\t\t}

\t\t\t\ttmp = state.y+state.height;

\t\t\t\tif (y+height > tmp)
\t\t\t\t{
\t\t\t\t\ty -= y+height - tmp;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (pgeo != null)
\t\t{
\t\t\tx -= pgeo.x*scale;
\t\t\ty -= pgeo.y*scale;
\t\t}
\t}

\tgeo = geo.clone();
\tgeo.x = this.graph.snap(x / scale -
\t\tthis.graph.getView().translate.x -
\t\tthis.graph.gridSize/2);
\tgeo.y = this.graph.snap(y / scale -
\t\tthis.graph.getView().translate.y -
\t\tthis.graph.gridSize/2);
\tvertex.setGeometry(geo);

\tif (parent == null)
\t{
\t\tparent = this.graph.getDefaultParent();
\t}

\tthis.cycleAttribute(vertex);
\tthis.fireEvent(new mxEventObject(mxEvent.BEFORE_ADD_VERTEX,
\t\t\t'vertex', vertex, 'parent', parent));

\tmodel.beginUpdate();
\ttry
\t{
\t\tvertex = this.graph.addCell(vertex, parent);

\t\tif (vertex != null)
\t\t{
\t\t\tthis.graph.constrainChild(vertex);

\t\t\tthis.fireEvent(new mxEventObject(mxEvent.ADD_VERTEX, 'vertex', vertex));
\t\t}
\t}
\tfinally
\t{
\t\tmodel.endUpdate();
\t}

\tif (vertex != null)
\t{
\t\tthis.graph.setSelectionCell(vertex);
\t\tthis.graph.scrollCellToVisible(vertex);
\t\tthis.fireEvent(new mxEventObject(mxEvent.AFTER_ADD_VERTEX, 'vertex', vertex));
\t}

\treturn vertex;
};

/**
 * Function: destroy
 *
 * Removes the editor and all its associated resources. This does not
 * normally need to be called, it is called automatically when the window
 * unloads.
 */
mxEditor.prototype.destroy = function ()
{
\tif (!this.destroyed)
\t{
\t\tthis.destroyed = true;

\t\tif (this.tasks != null)
\t\t{
\t\t\tthis.tasks.destroy();
\t\t}

\t\tif (this.outline != null)
\t\t{
\t\t\tthis.outline.destroy();
\t\t}

\t\tif (this.properties != null)
\t\t{
\t\t\tthis.properties.destroy();
\t\t}

\t\tif (this.keyHandler != null)
\t\t{
\t\t\tthis.keyHandler.destroy();
\t\t}

\t\tif (this.rubberband != null)
\t\t{
\t\t\tthis.rubberband.destroy();
\t\t}

\t\tif (this.toolbar != null)
\t\t{
\t\t\tthis.toolbar.destroy();
\t\t}

\t\tif (this.graph != null)
\t\t{
\t\t\tthis.graph.destroy();
\t\t}

\t\tthis.status = null;
\t\tthis.templates = null;
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxCodecRegistry =
{
\t/**
\t * Class: mxCodecRegistry
\t *
\t * Singleton class that acts as a global registry for codecs.
\t *
\t * Adding an <mxCodec>:
\t *
\t * 1. Define a default codec with a new instance of the 
\t * object to be handled.
\t *
\t * (code)
\t * var codec = new mxObjectCodec(new mxGraphModel());
\t * (end)
\t *
\t * 2. Define the functions required for encoding and decoding
\t * objects.
\t *
\t * (code)
\t * codec.encode = function(enc, obj) { ... }
\t * codec.decode = function(dec, node, into) { ... }
\t * (end)
\t *
\t * 3. Register the codec in the <mxCodecRegistry>.
\t *
\t * (code)
\t * mxCodecRegistry.register(codec);
\t * (end)
\t *
\t * <mxObjectCodec.decode> may be used to either create a new 
\t * instance of an object or to configure an existing instance, 
\t * in which case the into argument points to the existing
\t * object. In this case, we say the codec \"configures\" the
\t * object.
\t * 
\t * Variable: codecs
\t *
\t * Maps from constructor names to codecs.
\t */
\tcodecs: [],
\t
\t/**
\t * Variable: aliases
\t *
\t * Maps from classnames to codecnames.
\t */
\taliases: [],

\t/**
\t * Function: register
\t *
\t * Registers a new codec and associates the name of the template
\t * constructor in the codec with the codec object.
\t *
\t * Parameters:
\t *
\t * codec - <mxObjectCodec> to be registered.
\t */
\tregister: function(codec)
\t{
\t\tif (codec != null)
\t\t{
\t\t\tvar name = codec.getName();
\t\t\tmxCodecRegistry.codecs[name] = codec;
\t\t\t
\t\t\tvar classname = mxUtils.getFunctionName(codec.template.constructor);

\t\t\tif (classname != name)
\t\t\t{
\t\t\t\tmxCodecRegistry.addAlias(classname, name);
\t\t\t}
\t\t}

\t\treturn codec;
\t},

\t/**
\t * Function: addAlias
\t *
\t * Adds an alias for mapping a classname to a codecname.
\t */
\taddAlias: function(classname, codecname)
\t{
\t\tmxCodecRegistry.aliases[classname] = codecname;
\t},

\t/**
\t * Function: getCodec
\t *
\t * Returns a codec that handles objects that are constructed
\t * using the given constructor.
\t *
\t * Parameters:
\t *
\t * ctor - JavaScript constructor function. 
\t */
\tgetCodec: function(ctor)
\t{
\t\tvar codec = null;
\t\t
\t\tif (ctor != null)
\t\t{
\t\t\tvar name = mxUtils.getFunctionName(ctor);
\t\t\tvar tmp = mxCodecRegistry.aliases[name];
\t\t\t
\t\t\tif (tmp != null)
\t\t\t{
\t\t\t\tname = tmp;
\t\t\t}
\t\t\t
\t\t\tcodec = mxCodecRegistry.codecs[name];
\t\t\t
\t\t\t// Registers a new default codec for the given constructor
\t\t\t// if no codec has been previously defined.
\t\t\tif (codec == null)
\t\t\t{
\t\t\t\ttry
\t\t\t\t{
\t\t\t\t\tcodec = new mxObjectCodec(new ctor());
\t\t\t\t\tmxCodecRegistry.register(codec);
\t\t\t\t}
\t\t\t\tcatch (e)
\t\t\t\t{
\t\t\t\t\t// ignore
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn codec;
\t}

};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxCodec
 *
 * XML codec for JavaScript object graphs. See <mxObjectCodec> for a
 * description of the general encoding/decoding scheme. This class uses the
 * codecs registered in <mxCodecRegistry> for encoding/decoding each object.
 * 
 * References:
 * 
 * In order to resolve references, especially forward references, the mxCodec
 * constructor must be given the document that contains the referenced
 * elements.
 *
 * Examples:
 *
 * The following code is used to encode a graph model.
 *
 * (code)
 * var encoder = new mxCodec();
 * var result = encoder.encode(graph.getModel());
 * var xml = mxUtils.getXml(result);
 * (end)
 * 
 * Example:
 * 
 * Using the code below, an XML document is decoded into an existing model. The
 * document may be obtained using one of the functions in mxUtils for loading
 * an XML file, eg. <mxUtils.get>, or using <mxUtils.parseXml> for parsing an
 * XML string.
 * 
 * (code)
 * var doc = mxUtils.parseXml(xmlString);
 * var codec = new mxCodec(doc);
 * codec.decode(doc.documentElement, graph.getModel());
 * (end)
 * 
 * Example:
 * 
 * This example demonstrates parsing a list of isolated cells into an existing
 * graph model. Note that the cells do not have a parent reference so they can
 * be added anywhere in the cell hierarchy after parsing.
 * 
 * (code)
 * var xml = '<root><mxCell id=\"2\" value=\"Hello,\" vertex=\"1\"><mxGeometry x=\"20\" y=\"20\" width=\"80\" height=\"30\" as=\"geometry\"/></mxCell><mxCell id=\"3\" value=\"World!\" vertex=\"1\"><mxGeometry x=\"200\" y=\"150\" width=\"80\" height=\"30\" as=\"geometry\"/></mxCell><mxCell id=\"4\" value=\"\" edge=\"1\" source=\"2\" target=\"3\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell></root>';
 * var doc = mxUtils.parseXml(xml);
 * var codec = new mxCodec(doc);
 * var elt = doc.documentElement.firstChild;
 * var cells = [];
 * 
 * while (elt != null)
 * {
 *   cells.push(codec.decode(elt));
 *   elt = elt.nextSibling;
 * }
 * 
 * graph.addCells(cells);
 * (end)
 * 
 * Example:
 * 
 * Using the following code, the selection cells of a graph are encoded and the
 * output is displayed in a dialog box.
 * 
 * (code)
 * var enc = new mxCodec();
 * var cells = graph.getSelectionCells();
 * mxUtils.alert(mxUtils.getPrettyXml(enc.encode(cells)));
 * (end)
 * 
 * Newlines in the XML can be converted to <br>, in which case a '<br>' argument
 * must be passed to <mxUtils.getXml> as the second argument.
 * 
 * Debugging:
 * 
 * For debugging I/O you can use the following code to get the sequence of
 * encoded objects:
 * 
 * (code)
 * var oldEncode = mxCodec.prototype.encode;
 * mxCodec.prototype.encode = function(obj)
 * {
 *   mxLog.show();
 *   mxLog.debug('mxCodec.encode: obj='+mxUtils.getFunctionName(obj.constructor));
 *   
 *   return oldEncode.apply(this, arguments);
 * };
 * (end)
 * 
 * Note that the I/O system adds object codecs for new object automatically. For
 * decoding those objects, the constructor should be written as follows:
 * 
 * (code)
 * var MyObj = function(name)
 * {
 *   // ...
 * };
 * (end)
 * 
 * Constructor: mxCodec
 *
 * Constructs an XML encoder/decoder for the specified
 * owner document.
 *
 * Parameters:
 *
 * document - Optional XML document that contains the data.
 * If no document is specified then a new document is created
 * using <mxUtils.createXmlDocument>.
 */
function mxCodec(document)
{
\tthis.document = document || mxUtils.createXmlDocument();
\tthis.objects = [];
};

/**
 * Variable: document
 *
 * The owner document of the codec.
 */
mxCodec.prototype.document = null;

/**
 * Variable: objects
 *
 * Maps from IDs to objects.
 */
mxCodec.prototype.objects = null;

/**
 * Variable: elements
 * 
 * Lookup table for resolving IDs to elements.
 */
mxCodec.prototype.elements = null;

/**
 * Variable: encodeDefaults
 *
 * Specifies if default values should be encoded. Default is false.
 */
mxCodec.prototype.encodeDefaults = false;


/**
 * Function: putObject
 * 
 * Assoiates the given object with the given ID and returns the given object.
 * 
 * Parameters
 * 
 * id - ID for the object to be associated with.
 * obj - Object to be associated with the ID.
 */
mxCodec.prototype.putObject = function(id, obj)
{
\tthis.objects[id] = obj;
\t
\treturn obj;
};

/**
 * Function: getObject
 *
 * Returns the decoded object for the element with the specified ID in
 * <document>. If the object is not known then <lookup> is used to find an
 * object. If no object is found, then the element with the respective ID
 * from the document is parsed using <decode>.
 */
mxCodec.prototype.getObject = function(id)
{
\tvar obj = null;

\tif (id != null)
\t{
\t\tobj = this.objects[id];
\t\t
\t\tif (obj == null)
\t\t{
\t\t\tobj = this.lookup(id);
\t\t\t
\t\t\tif (obj == null)
\t\t\t{
\t\t\t\tvar node = this.getElementById(id);
\t\t\t\t
\t\t\t\tif (node != null)
\t\t\t\t{
\t\t\t\t\tobj = this.decode(node);
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn obj;
};

/**
 * Function: lookup
 *
 * Hook for subclassers to implement a custom lookup mechanism for cell IDs.
 * This implementation always returns null.
 *
 * Example:
 *
 * (code)
 * var codec = new mxCodec();
 * codec.lookup = function(id)
 * {
 *   return model.getCell(id);
 * };
 * (end)
 *
 * Parameters:
 *
 * id - ID of the object to be returned.
 */
mxCodec.prototype.lookup = function(id)
{
\treturn null;
};

/**
 * Function: getElementById
 *
 * Returns the element with the given ID from <document>.
 *
 * Parameters:
 *
 * id - String that contains the ID.
 */
mxCodec.prototype.getElementById = function(id)
{
\tthis.updateElements();
\t
\treturn this.elements[id];
};

/**
 * Function: updateElements
 *
 * Returns the element with the given ID from <document>.
 *
 * Parameters:
 *
 * id - String that contains the ID.
 */
mxCodec.prototype.updateElements = function()
{
\tif (this.elements == null)
\t{
\t\tthis.elements = new Object();
\t\t
\t\tif (this.document.documentElement != null)
\t\t{
\t\t\tthis.addElement(this.document.documentElement);
\t\t}
\t}
};

/**
 * Function: addElement
 *
 * Adds the given element to <elements> if it has an ID.
 */
mxCodec.prototype.addElement = function(node)
{
\tif (node.nodeType == mxConstants.NODETYPE_ELEMENT)
\t{
\t\tvar id = node.getAttribute('id');
\t\t
\t\tif (id != null)
\t\t{
\t\t\tif (this.elements[id] == null)
\t\t\t{
\t\t\t\tthis.elements[id] = node;
\t\t\t}
\t\t\telse if (this.elements[id] != node)
\t\t\t{
\t\t\t\tthrow new Error(id + ': Duplicate ID');
\t\t\t}
\t\t}
\t}
\t
\tnode = node.firstChild;
\t
\twhile (node != null)
\t{
\t\tthis.addElement(node);
\t\tnode = node.nextSibling;
\t}
};

/**
 * Function: getId
 *
 * Returns the ID of the specified object. This implementation
 * calls <reference> first and if that returns null handles
 * the object as an <mxCell> by returning their IDs using
 * <mxCell.getId>. If no ID exists for the given cell, then
 * an on-the-fly ID is generated using <mxCellPath.create>.
 *
 * Parameters:
 *
 * obj - Object to return the ID for.
 */
mxCodec.prototype.getId = function(obj)
{
\tvar id = null;
\t
\tif (obj != null)
\t{
\t\tid = this.reference(obj);
\t\t
\t\tif (id == null && obj instanceof mxCell)
\t\t{
\t\t\tid = obj.getId();
\t\t\t
\t\t\tif (id == null)
\t\t\t{
\t\t\t\t// Uses an on-the-fly Id
\t\t\t\tid = mxCellPath.create(obj);
\t\t\t\t
\t\t\t\tif (id.length == 0)
\t\t\t\t{
\t\t\t\t\tid = 'root';
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\t
\treturn id;
};

/**
 * Function: reference
 *
 * Hook for subclassers to implement a custom method
 * for retrieving IDs from objects. This implementation
 * always returns null.
 *
 * Example:
 *
 * (code)
 * var codec = new mxCodec();
 * codec.reference = function(obj)
 * {
 *   return obj.getCustomId();
 * };
 * (end)
 *
 * Parameters:
 *
 * obj - Object whose ID should be returned.
 */
mxCodec.prototype.reference = function(obj)
{
\treturn null;
};

/**
 * Function: encode
 *
 * Encodes the specified object and returns the resulting
 * XML node.
 *
 * Parameters:
 *
 * obj - Object to be encoded. 
 */
mxCodec.prototype.encode = function(obj)
{
\tvar node = null;
\t
\tif (obj != null && obj.constructor != null)
\t{
\t\tvar enc = mxCodecRegistry.getCodec(obj.constructor);
\t\t
\t\tif (enc != null)
\t\t{
\t\t\tnode = enc.encode(this, obj);
\t\t}
\t\telse
\t\t{
\t\t\tif (mxUtils.isNode(obj))
\t\t\t{
\t\t\t\tnode = mxUtils.importNode(this.document, obj, true);
\t\t\t}
\t\t\telse
\t\t\t{
\t    \t\tmxLog.warn('mxCodec.encode: No codec for ' + mxUtils.getFunctionName(obj.constructor));
\t\t\t}
\t\t}
\t}
\t
\treturn node;
};

/**
 * Function: decode
 *
 * Decodes the given XML node. The optional \"into\"
 * argument specifies an existing object to be
 * used. If no object is given, then a new instance
 * is created using the constructor from the codec.
 *
 * The function returns the passed in object or
 * the new instance if no object was given.
 *
 * Parameters:
 *
 * node - XML node to be decoded.
 * into - Optional object to be decodec into.
 */
mxCodec.prototype.decode = function(node, into)
{
\tthis.updateElements();
\tvar obj = null;
\t
\tif (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
\t{
\t\tvar ctor = null;
\t\t
\t\ttry
\t\t{
\t\t\tctor = window[node.nodeName];
\t\t}
\t\tcatch (err)
\t\t{
\t\t\t// ignore
\t\t}
\t\t
\t\tvar dec = mxCodecRegistry.getCodec(ctor);
\t\t
\t\tif (dec != null)
\t\t{
\t\t\tobj = dec.decode(this, node, into);
\t\t}
\t\telse
\t\t{
\t\t\tobj = node.cloneNode(true);
\t\t\tobj.removeAttribute('as');
\t\t}
\t}
\t
\treturn obj;
};

/**
 * Function: encodeCell
 *
 * Encoding of cell hierarchies is built-into the core, but
 * is a higher-level function that needs to be explicitely
 * used by the respective object encoders (eg. <mxModelCodec>,
 * <mxChildChangeCodec> and <mxRootChangeCodec>). This
 * implementation writes the given cell and its children as a
 * (flat) sequence into the given node. The children are not
 * encoded if the optional includeChildren is false. The
 * function is in charge of adding the result into the
 * given node and has no return value.
 *
 * Parameters:
 *
 * cell - <mxCell> to be encoded.
 * node - Parent XML node to add the encoded cell into.
 * includeChildren - Optional boolean indicating if the
 * function should include all descendents. Default is true. 
 */
mxCodec.prototype.encodeCell = function(cell, node, includeChildren)
{
\tnode.appendChild(this.encode(cell));
\t
\tif (includeChildren == null || includeChildren)
\t{
\t\tvar childCount = cell.getChildCount();
\t\t
\t\tfor (var i = 0; i < childCount; i++)
\t\t{
\t\t\tthis.encodeCell(cell.getChildAt(i), node);
\t\t}
\t}
};

/**
 * Function: isCellCodec
 * 
 * Returns true if the given codec is a cell codec. This uses
 * <mxCellCodec.isCellCodec> to check if the codec is of the
 * given type.
 */
mxCodec.prototype.isCellCodec = function(codec)
{
\tif (codec != null && typeof(codec.isCellCodec) == 'function')
\t{
\t\treturn codec.isCellCodec();
\t}
\t
\treturn false;
};

/**
 * Function: decodeCell
 *
 * Decodes cells that have been encoded using inversion, ie.
 * where the user object is the enclosing node in the XML,
 * and restores the group and graph structure in the cells.
 * Returns a new <mxCell> instance that represents the
 * given node.
 *
 * Parameters:
 *
 * node - XML node that contains the cell data.
 * restoreStructures - Optional boolean indicating whether
 * the graph structure should be restored by calling insert
 * and insertEdge on the parent and terminals, respectively.
 * Default is true.
 */
mxCodec.prototype.decodeCell = function(node, restoreStructures)
{
\trestoreStructures = (restoreStructures != null) ? restoreStructures : true;
\tvar cell = null;
\t
\tif (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
\t{
\t\t// Tries to find a codec for the given node name. If that does
\t\t// not return a codec then the node is the user object (an XML node
\t\t// that contains the mxCell, aka inversion).
\t\tvar decoder = mxCodecRegistry.getCodec(node.nodeName);
\t\t
\t\t// Tries to find the codec for the cell inside the user object.
\t\t// This assumes all node names inside the user object are either
\t\t// not registered or they correspond to a class for cells.
\t\tif (!this.isCellCodec(decoder))
\t\t{
\t\t\tvar child = node.firstChild;
\t\t\t
\t\t\twhile (child != null && !this.isCellCodec(decoder))
\t\t\t{
\t\t\t\tdecoder = mxCodecRegistry.getCodec(child.nodeName);
\t\t\t\tchild = child.nextSibling;
\t\t\t}
\t\t}
\t\t
\t\tif (!this.isCellCodec(decoder))
\t\t{
\t\t\tdecoder = mxCodecRegistry.getCodec(mxCell);
\t\t}

\t\tcell = decoder.decode(this, node);
\t\t
\t\tif (restoreStructures)
\t\t{
\t\t\tthis.insertIntoGraph(cell);
\t\t}
\t}
\t
\treturn cell;
};

/**
 * Function: insertIntoGraph
 *
 * Inserts the given cell into its parent and terminal cells.
 */
mxCodec.prototype.insertIntoGraph = function(cell)
{
\tvar parent = cell.parent;
\tvar source = cell.getTerminal(true);
\tvar target = cell.getTerminal(false);

\t// Fixes possible inconsistencies during insert into graph
\tcell.setTerminal(null, false);
\tcell.setTerminal(null, true);
\tcell.parent = null;
\t
\tif (parent != null)
\t{
\t\tif (parent == cell)
\t\t{
\t\t\tthrow new Error(parent.id + ': Self Reference');
\t\t}
\t\telse
\t\t{
\t\t\tparent.insert(cell);
\t\t}
\t}

\tif (source != null)
\t{
\t\tsource.insertEdge(cell, true);
\t}

\tif (target != null)
\t{
\t\ttarget.insertEdge(cell, false);
\t}
};

/**
 * Function: setAttribute
 *
 * Sets the attribute on the specified node to value. This is a
 * helper method that makes sure the attribute and value arguments
 * are not null.
 *
 * Parameters:
 *
 * node - XML node to set the attribute for.
 * attributes - Attributename to be set.
 * value - New value of the attribute.
 */
mxCodec.prototype.setAttribute = function(node, attribute, value)
{
\tif (attribute != null && value != null)
\t{
\t\tnode.setAttribute(attribute, value);
\t}
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxObjectCodec
 *
 * Generic codec for JavaScript objects that implements a mapping between
 * JavaScript objects and XML nodes that maps each field or element to an
 * attribute or child node, and vice versa.
 * 
 * Atomic Values:
 * 
 * Consider the following example.
 * 
 * (code)
 * var obj = new Object();
 * obj.foo = \"Foo\";
 * obj.bar = \"Bar\";
 * (end)
 * 
 * This object is encoded into an XML node using the following.
 * 
 * (code)
 * var enc = new mxCodec();
 * var node = enc.encode(obj);
 * (end)
 * 
 * The output of the encoding may be viewed using <mxLog> as follows.
 * 
 * (code)
 * mxLog.show();
 * mxLog.debug(mxUtils.getPrettyXml(node));
 * (end)
 * 
 * Finally, the result of the encoding looks as follows.
 * 
 * (code)
 * <Object foo=\"Foo\" bar=\"Bar\"/>
 * (end)
 * 
 * In the above output, the foo and bar fields have been mapped to attributes
 * with the same names, and the name of the constructor was used for the
 * nodename.
 * 
 * Booleans:
 *
 * Since booleans are numbers in JavaScript, all boolean values are encoded
 * into 1 for true and 0 for false. The decoder also accepts the string true
 * and false for boolean values.
 * 
 * Objects:
 * 
 * The above scheme is applied to all atomic fields, that is, to all non-object
 * fields of an object. For object fields, a child node is created with a
 * special attribute that contains the fieldname. This special attribute is
 * called \"as\" and hence, as is a reserved word that should not be used for a
 * fieldname.
 * 
 * Consider the following example where foo is an object and bar is an atomic
 * property of foo.
 * 
 * (code)
 * var obj = {foo: {bar: \"Bar\"}};
 * (end)
 * 
 * This will be mapped to the following XML structure by mxObjectCodec.
 * 
 * (code)
 * <Object>
 *   <Object bar=\"Bar\" as=\"foo\"/>
 * </Object>
 * (end)
 * 
 * In the above output, the inner Object node contains the as-attribute that
 * specifies the fieldname in the enclosing object. That is, the field foo was
 * mapped to a child node with an as-attribute that has the value foo.
 * 
 * Arrays:
 * 
 * Arrays are special objects that are either associative, in which case each
 * key, value pair is treated like a field where the key is the fieldname, or
 * they are a sequence of atomic values and objects, which is mapped to a
 * sequence of child nodes. For object elements, the above scheme is applied
 * without the use of the special as-attribute for creating each child. For
 * atomic elements, a special add-node is created with the value stored in the
 * value-attribute.
 * 
 * For example, the following array contains one atomic value and one object
 * with a field called bar. Furthermore it contains two associative entries
 * called bar with an atomic value, and foo with an object value.
 * 
 * (code)
 * var obj = [\"Bar\", {bar: \"Bar\"}];
 * obj[\"bar\"] = \"Bar\";
 * obj[\"foo\"] = {bar: \"Bar\"};
 * (end)
 * 
 * This array is represented by the following XML nodes.
 * 
 * (code)
 * <Array bar=\"Bar\">
 *   <add value=\"Bar\"/>
 *   <Object bar=\"Bar\"/>
 *   <Object bar=\"Bar\" as=\"foo\"/>
 * </Array>
 * (end)
 * 
 * The Array node name is the name of the constructor. The additional
 * as-attribute in the last child contains the key of the associative entry,
 * whereas the second last child is part of the array sequence and does not
 * have an as-attribute.
 * 
 * References:
 * 
 * Objects may be represented as child nodes or attributes with ID values,
 * which are used to lookup the object in a table within <mxCodec>. The
 * <isReference> function is in charge of deciding if a specific field should
 * be encoded as a reference or not. Its default implementation returns true if
 * the fieldname is in <idrefs>, an array of strings that is used to configure
 * the <mxObjectCodec>.
 * 
 * Using this approach, the mapping does not guarantee that the referenced
 * object itself exists in the document. The fields that are encoded as
 * references must be carefully chosen to make sure all referenced objects
 * exist in the document, or may be resolved by some other means if necessary.
 * 
 * For example, in the case of the graph model all cells are stored in a tree
 * whose root is referenced by the model's root field. A tree is a structure
 * that is well suited for an XML representation, however, the additional edges
 * in the graph model have a reference to a source and target cell, which are
 * also contained in the tree. To handle this case, the source and target cell
 * of an edge are treated as references, whereas the children are treated as
 * objects. Since all cells are contained in the tree and no edge references a
 * source or target outside the tree, this setup makes sure all referenced
 * objects are contained in the document.
 * 
 * In the case of a tree structure we must further avoid infinite recursion by
 * ignoring the parent reference of each child. This is done by returning true
 * in <isExcluded>, whose default implementation uses the array of excluded
 * fieldnames passed to the mxObjectCodec constructor.
 * 
 * References are only used for cells in mxGraph. For defining other
 * referencable object types, the codec must be able to work out the ID of an
 * object. This is done by implementing <mxCodec.reference>. For decoding a
 * reference, the XML node with the respective id-attribute is fetched from the
 * document, decoded, and stored in a lookup table for later reference. For
 * looking up external objects, <mxCodec.lookup> may be implemented.
 * 
 * Expressions:
 * 
 * For decoding JavaScript expressions, the add-node may be used with a text
 * content that contains the JavaScript expression. For example, the following
 * creates a field called foo in the enclosing object and assigns it the value
 * of <mxConstants.ALIGN_LEFT>.
 * 
 * (code)
 * <Object>
 *   <add as=\"foo\">mxConstants.ALIGN_LEFT</add>
 * </Object>
 * (end)
 * 
 * The resulting object has a field called foo with the value \"left\". Its XML
 * representation looks as follows.
 * 
 * (code)
 * <Object foo=\"left\"/>
 * (end)
 * 
 * This means the expression is evaluated at decoding time and the result of
 * the evaluation is stored in the respective field. Valid expressions are all
 * JavaScript expressions, including function definitions, which are mapped to
 * functions on the resulting object.
 * 
 * Expressions are only evaluated if <allowEval> is true.
 * 
 * Constructor: mxObjectCodec
 *
 * Constructs a new codec for the specified template object.
 * The variables in the optional exclude array are ignored by
 * the codec. Variables in the optional idrefs array are
 * turned into references in the XML. The optional mapping
 * may be used to map from variable names to XML attributes.
 * The argument is created as follows:
 *
 * (code)
 * var mapping = new Object();
 * mapping['variableName'] = 'attribute-name';
 * (end)
 *
 * Parameters:
 *
 * template - Prototypical instance of the object to be
 * encoded/decoded.
 * exclude - Optional array of fieldnames to be ignored.
 * idrefs - Optional array of fieldnames to be converted to/from
 * references.
 * mapping - Optional mapping from field- to attributenames.
 */
function mxObjectCodec(template, exclude, idrefs, mapping)
{
\tthis.template = template;
\t
\tthis.exclude = (exclude != null) ? exclude : [];
\tthis.idrefs = (idrefs != null) ? idrefs : [];
\tthis.mapping = (mapping != null) ? mapping : [];
\t
\tthis.reverse = new Object();
\t
\tfor (var i in this.mapping)
\t{
\t\tthis.reverse[this.mapping[i]] = i;
\t}
};

/**
 * Variable: allowEval
 *
 * Static global switch that specifies if expressions in arrays are allowed.
 * Default is false. NOTE: Enabling this carries a possible security risk.
 */
mxObjectCodec.allowEval = false;

/**
 * Variable: template
 *
 * Holds the template object associated with this codec.
 */
mxObjectCodec.prototype.template = null;

/**
 * Variable: exclude
 *
 * Array containing the variable names that should be
 * ignored by the codec.
 */
mxObjectCodec.prototype.exclude = null;

/**
 * Variable: idrefs
 *
 * Array containing the variable names that should be
 * turned into or converted from references. See
 * <mxCodec.getId> and <mxCodec.getObject>.
 */
mxObjectCodec.prototype.idrefs = null;

/**
 * Variable: mapping
 *
 * Maps from from fieldnames to XML attribute names.
 */
mxObjectCodec.prototype.mapping = null;

/**
 * Variable: reverse
 *
 * Maps from from XML attribute names to fieldnames.
 */
mxObjectCodec.prototype.reverse = null;

/**
 * Function: getName
 * 
 * Returns the name used for the nodenames and lookup of the codec when
 * classes are encoded and nodes are decoded. For classes to work with
 * this the codec registry automatically adds an alias for the classname
 * if that is different than what this returns. The default implementation
 * returns the classname of the template class.
 */
mxObjectCodec.prototype.getName = function()
{
\treturn mxUtils.getFunctionName(this.template.constructor);
};

/**
 * Function: cloneTemplate
 * 
 * Returns a new instance of the template for this codec.
 */
mxObjectCodec.prototype.cloneTemplate = function()
{
\treturn new this.template.constructor();
};

/**
 * Function: getFieldName
 * 
 * Returns the fieldname for the given attributename.
 * Looks up the value in the <reverse> mapping or returns
 * the input if there is no reverse mapping for the
 * given name.
 */
mxObjectCodec.prototype.getFieldName = function(attributename)
{
\tif (attributename != null)
\t{
\t\tvar mapped = this.reverse[attributename];
\t\t
\t\tif (mapped != null)
\t\t{
\t\t\tattributename = mapped;
\t\t}
\t}
\t
\treturn attributename;
};

/**
 * Function: getAttributeName
 * 
 * Returns the attributename for the given fieldname.
 * Looks up the value in the <mapping> or returns
 * the input if there is no mapping for the
 * given name.
 */
mxObjectCodec.prototype.getAttributeName = function(fieldname)
{
\tif (fieldname != null)
\t{
\t\tvar mapped = this.mapping[fieldname];
\t\t
\t\tif (mapped != null)
\t\t{
\t\t\tfieldname = mapped;
\t\t}
\t}
\t
\treturn fieldname;
};

/**
 * Function: isExcluded
 *
 * Returns true if the given attribute is to be ignored by the codec. This
 * implementation returns true if the given fieldname is in <exclude> or
 * if the fieldname equals <mxObjectIdentity.FIELD_NAME>.
 *
 * Parameters:
 *
 * obj - Object instance that contains the field.
 * attr - Fieldname of the field.
 * value - Value of the field.
 * write - Boolean indicating if the field is being encoded or decoded.
 * Write is true if the field is being encoded, else it is being decoded.
 */
mxObjectCodec.prototype.isExcluded = function(obj, attr, value, write)
{
\treturn attr == mxObjectIdentity.FIELD_NAME ||
\t\tmxUtils.indexOf(this.exclude, attr) >= 0;
};

/**
 * Function: isReference
 *
 * Returns true if the given fieldname is to be treated
 * as a textual reference (ID). This implementation returns
 * true if the given fieldname is in <idrefs>.
 *
 * Parameters:
 *
 * obj - Object instance that contains the field.
 * attr - Fieldname of the field.
 * value - Value of the field. 
 * write - Boolean indicating if the field is being encoded or decoded.
 * Write is true if the field is being encoded, else it is being decoded.
 */
mxObjectCodec.prototype.isReference = function(obj, attr, value, write)
{
\treturn mxUtils.indexOf(this.idrefs, attr) >= 0;
};

/**
 * Function: encode
 *
 * Encodes the specified object and returns a node
 * representing then given object. Calls <beforeEncode>
 * after creating the node and <afterEncode> with the 
 * resulting node after processing.
 *
 * Enc is a reference to the calling encoder. It is used
 * to encode complex objects and create references.
 *
 * This implementation encodes all variables of an
 * object according to the following rules:
 *
 * - If the variable name is in <exclude> then it is ignored.
 * - If the variable name is in <idrefs> then <mxCodec.getId>
 * is used to replace the object with its ID.
 * - The variable name is mapped using <mapping>.
 * - If obj is an array and the variable name is numeric
 * (ie. an index) then it is not encoded.
 * - If the value is an object, then the codec is used to
 * create a child node with the variable name encoded into
 * the \"as\" attribute.
 * - Else, if <encodeDefaults> is true or the value differs
 * from the template value, then ...
 * - ... if obj is not an array, then the value is mapped to
 * an attribute.
 * - ... else if obj is an array, the value is mapped to an
 * add child with a value attribute or a text child node,
 * if the value is a function.
 *
 * If no ID exists for a variable in <idrefs> or if an object
 * cannot be encoded, a warning is issued using <mxLog.warn>.
 *
 * Returns the resulting XML node that represents the given
 * object.
 *
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Object to be encoded.
 */
mxObjectCodec.prototype.encode = function(enc, obj)
{
\tvar node = enc.document.createElement(this.getName());
\t
\tobj = this.beforeEncode(enc, obj, node);
\tthis.encodeObject(enc, obj, node);
\t
\treturn this.afterEncode(enc, obj, node);
};
\t
/**
 * Function: encodeObject
 *
 * Encodes the value of each member in then given obj into the given node using
 * <encodeValue>.
 * 
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Object to be encoded.
 * node - XML node that contains the encoded object.
 */
mxObjectCodec.prototype.encodeObject = function(enc, obj, node)
{
\tenc.setAttribute(node, 'id', enc.getId(obj));
\t
    for (var i in obj)
    {
\t\tvar name = i;
\t\tvar value = obj[name];
\t\t
    \tif (value != null && !this.isExcluded(obj, name, value, true))
    \t{
    \t\tif (mxUtils.isInteger(name))
    \t\t{
    \t\t\tname = null;
    \t\t}
    \t\t
    \t\tthis.encodeValue(enc, obj, name, value, node);
    \t}
    }
};

/**
 * Function: encodeValue
 * 
 * Converts the given value according to the mappings
 * and id-refs in this codec and uses <writeAttribute>
 * to write the attribute into the given node.
 * 
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Object whose property is going to be encoded.
 * name - XML node that contains the encoded object.
 * value - Value of the property to be encoded.
 * node - XML node that contains the encoded object.
 */
mxObjectCodec.prototype.encodeValue = function(enc, obj, name, value, node)
{
\tif (value != null)
\t{
\t\tif (this.isReference(obj, name, value, true))
\t\t{
\t\t\tvar tmp = enc.getId(value);
\t\t\t
\t\t\tif (tmp == null)
\t\t\t{
\t\t    \tmxLog.warn('mxObjectCodec.encode: No ID for ' +
\t\t    \t\tthis.getName() + '.' + name + '=' + value);
\t\t    \treturn; // exit
\t\t    }
\t\t    
\t\t    value = tmp;
\t\t}

\t\tvar defaultValue = this.template[name];
\t\t
\t\t// Checks if the value is a default value and
\t\t// the name is correct
\t\tif (name == null || enc.encodeDefaults || defaultValue != value)
\t\t{
\t\t\tname = this.getAttributeName(name);
\t\t\tthis.writeAttribute(enc, obj, name, value, node);\t
\t\t}
\t}
};

/**
 * Function: writeAttribute
 * 
 * Writes the given value into node using <writePrimitiveAttribute>
 * or <writeComplexAttribute> depending on the type of the value.
 */
mxObjectCodec.prototype.writeAttribute = function(enc, obj, name, value, node)
{
\tif (typeof(value) != 'object' /* primitive type */)
\t{
\t\tthis.writePrimitiveAttribute(enc, obj, name, value, node);
\t}
\telse /* complex type */
\t{
\t\tthis.writeComplexAttribute(enc, obj, name, value, node);
\t}
};

/**
 * Function: writePrimitiveAttribute
 * 
 * Writes the given value as an attribute of the given node.
 */
mxObjectCodec.prototype.writePrimitiveAttribute = function(enc, obj, name, value, node)
{
\tvalue = this.convertAttributeToXml(enc, obj, name, value, node);
\t
\tif (name == null)
\t{
\t\tvar child = enc.document.createElement('add');
\t\t
\t\tif (typeof(value) == 'function')
\t\t{
    \t\tchild.appendChild(enc.document.createTextNode(value));
    \t}
    \telse
    \t{
    \t\tenc.setAttribute(child, 'value', value);
    \t}
    \t
\t\tnode.appendChild(child);
\t}
\telse if (typeof(value) != 'function')
\t{
    \tenc.setAttribute(node, name, value);
\t}\t\t
};
\t
/**
 * Function: writeComplexAttribute
 * 
 * Writes the given value as a child node of the given node.
 */
mxObjectCodec.prototype.writeComplexAttribute = function(enc, obj, name, value, node)
{
\tvar child = enc.encode(value);
\t
\tif (child != null)
\t{
\t\tif (name != null)
\t\t{
    \t\tchild.setAttribute('as', name);
    \t}
    \t
    \tnode.appendChild(child);
\t}
\telse
\t{
\t\tmxLog.warn('mxObjectCodec.encode: No node for ' + this.getName() + '.' + name + ': ' + value);
\t}
};

/**
 * Function: convertAttributeToXml
 * 
 * Converts true to \"1\" and false to \"0\" is <isBooleanAttribute> returns true.
 * All other values are not converted.
 * 
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Objec to convert the attribute for.
 * name - Name of the attribute to be converted.
 * value - Value to be converted.
 */
mxObjectCodec.prototype.convertAttributeToXml = function(enc, obj, name, value)
{
\t// Makes sure to encode boolean values as numeric values
\tif (this.isBooleanAttribute(enc, obj, name, value))
\t{\t
\t\t// Checks if the value is true (do not use the value as is, because
\t\t// this would check if the value is not null, so 0 would be true)
\t\tvalue = (value == true) ? '1' : '0';
\t}
\t
\treturn value;
};

/**
 * Function: isBooleanAttribute
 * 
 * Returns true if the given object attribute is a boolean value.
 * 
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Objec to convert the attribute for.
 * name - Name of the attribute to be converted.
 * value - Value of the attribute to be converted.
 */
mxObjectCodec.prototype.isBooleanAttribute = function(enc, obj, name, value)
{
\treturn (typeof(value.length) == 'undefined' && (value == true || value == false));
};

/**
 * Function: convertAttributeFromXml
 * 
 * Converts booleans and numeric values to the respective types. Values are
 * numeric if <isNumericAttribute> returns true.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * attr - XML attribute to be converted.
 * obj - Objec to convert the attribute for.
 */
mxObjectCodec.prototype.convertAttributeFromXml = function(dec, attr, obj)
{
\tvar value = attr.value;
\t
\tif (this.isNumericAttribute(dec, attr, obj))
\t{
\t\tvalue = parseFloat(value);
\t\t
\t\tif (isNaN(value) || !isFinite(value))
\t\t{
\t\t\tvalue = 0;
\t\t}
\t}
\t
\treturn value;
};

/**
 * Function: isNumericAttribute
 * 
 * Returns true if the given XML attribute is or should be a numeric value.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * attr - XML attribute to be converted.
 * obj - Objec to convert the attribute for.
 */
mxObjectCodec.prototype.isNumericAttribute = function(dec, attr, obj)
{
\t// Handles known numeric attributes for generic objects
\tvar result = (obj.constructor == mxGeometry &&
\t\t(attr.name == 'x' || attr.name == 'y' ||
\t\tattr.name == 'width' || attr.name == 'height')) ||
\t\t(obj.constructor == mxPoint &&
\t\t(attr.name == 'x' || attr.name == 'y')) ||
\t\tmxUtils.isNumeric(attr.value);
\t
\treturn result;
};

/**
 * Function: beforeEncode
 *
 * Hook for subclassers to pre-process the object before
 * encoding. This returns the input object. The return
 * value of this function is used in <encode> to perform
 * the default encoding into the given node.
 *
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Object to be encoded.
 * node - XML node to encode the object into.
 */
mxObjectCodec.prototype.beforeEncode = function(enc, obj, node)
{
\treturn obj;
};

/**
 * Function: afterEncode
 *
 * Hook for subclassers to post-process the node
 * for the given object after encoding and return the
 * post-processed node. This implementation returns 
 * the input node. The return value of this method
 * is returned to the encoder from <encode>.
 *
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * obj - Object to be encoded.
 * node - XML node that represents the default encoding.
 */
mxObjectCodec.prototype.afterEncode = function(enc, obj, node)
{
\treturn node;
};

/**
 * Function: decode
 *
 * Parses the given node into the object or returns a new object
 * representing the given node.
 *
 * Dec is a reference to the calling decoder. It is used to decode
 * complex objects and resolve references.
 *
 * If a node has an id attribute then the object cache is checked for the
 * object. If the object is not yet in the cache then it is constructed
 * using the constructor of <template> and cached in <mxCodec.objects>.
 *
 * This implementation decodes all attributes and childs of a node
 * according to the following rules:
 *
 * - If the variable name is in <exclude> or if the attribute name is \"id\"
 * or \"as\" then it is ignored.
 * - If the variable name is in <idrefs> then <mxCodec.getObject> is used
 * to replace the reference with an object.
 * - The variable name is mapped using a reverse <mapping>.
 * - If the value has a child node, then the codec is used to create a
 * child object with the variable name taken from the \"as\" attribute.
 * - If the object is an array and the variable name is empty then the
 * value or child object is appended to the array.
 * - If an add child has no value or the object is not an array then
 * the child text content is evaluated using <mxUtils.eval>.
 *
 * For add nodes where the object is not an array and the variable name
 * is defined, the default mechanism is used, allowing to override/add
 * methods as follows:
 *
 * (code)
 * <Object>
 *   <add as=\"hello\"><![CDATA[
 *     function(arg1) {
 *       mxUtils.alert('Hello '+arg1);
 *     }
 *   ]]></add>
 * </Object>
 * (end) 
 *
 * If no object exists for an ID in <idrefs> a warning is issued
 * using <mxLog.warn>.
 *
 * Returns the resulting object that represents the given XML node
 * or the object given to the method as the into parameter.
 *
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * node - XML node to be decoded.
 * into - Optional objec to encode the node into.
 */
mxObjectCodec.prototype.decode = function(dec, node, into)
{
\tvar id = node.getAttribute('id');
\tvar obj = dec.objects[id];
\t
\tif (obj == null)
\t{
\t\tobj = into || this.cloneTemplate();
\t\t
\t\tif (id != null)
\t\t{
\t\t\tdec.putObject(id, obj);
\t\t}
\t}
\t
\tnode = this.beforeDecode(dec, node, obj);
\tthis.decodeNode(dec, node, obj);
\t
    return this.afterDecode(dec, node, obj);
};\t

/**
 * Function: decodeNode
 * 
 * Calls <decodeAttributes> and <decodeChildren> for the given node.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * node - XML node to be decoded.
 * obj - Objec to encode the node into.
 */\t
mxObjectCodec.prototype.decodeNode = function(dec, node, obj)
{
\tif (node != null)
\t{
\t\tthis.decodeAttributes(dec, node, obj);
\t\tthis.decodeChildren(dec, node, obj);
\t}
};

/**
 * Function: decodeAttributes
 * 
 * Decodes all attributes of the given node using <decodeAttribute>.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * node - XML node to be decoded.
 * obj - Objec to encode the node into.
 */\t
mxObjectCodec.prototype.decodeAttributes = function(dec, node, obj)
{
\tvar attrs = node.attributes;
\t
\tif (attrs != null)
\t{
\t\tfor (var i = 0; i < attrs.length; i++)
\t\t{
\t\t\tthis.decodeAttribute(dec, attrs[i], obj);
\t\t}
\t}
};

/**
 * Function: isIgnoredAttribute
 * 
 * Returns true if the given attribute should be ignored. This implementation
 * returns true if the attribute name is \"as\" or \"id\".
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * attr - XML attribute to be decoded.
 * obj - Objec to encode the attribute into.
 */\t
mxObjectCodec.prototype.isIgnoredAttribute = function(dec, attr, obj)
{
\treturn attr.nodeName == 'as' || attr.nodeName == 'id';
};

/**
 * Function: decodeAttribute
 * 
 * Reads the given attribute into the specified object.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * attr - XML attribute to be decoded.
 * obj - Objec to encode the attribute into.
 */\t
mxObjectCodec.prototype.decodeAttribute = function(dec, attr, obj)
{
\tif (!this.isIgnoredAttribute(dec, attr, obj))
\t{
\t\tvar name = attr.nodeName;
\t\t
\t\t// Converts the string true and false to their boolean values.
\t\t// This may require an additional check on the obj to see if
\t\t// the existing field is a boolean value or uninitialized, in
\t\t// which case we may want to convert true and false to a string.
\t\tvar value = this.convertAttributeFromXml(dec, attr, obj);
\t\tvar fieldname = this.getFieldName(name);
\t\t
\t\tif (this.isReference(obj, fieldname, value, false))
\t\t{
\t\t\tvar tmp = dec.getObject(value);
\t\t\t
\t\t\tif (tmp == null)
\t\t\t{
\t\t    \tmxLog.warn('mxObjectCodec.decode: No object for ' +
\t\t    \t\tthis.getName() + '.' + name + '=' + value);
\t\t    \treturn; // exit
\t\t    }
\t\t    
\t\t    value = tmp;
\t\t}

\t\tif (!this.isExcluded(obj, name, value, false))
\t\t{
\t\t\t//mxLog.debug(mxUtils.getFunctionName(obj.constructor)+'.'+name+'='+value);
\t\t\tobj[name] = value;
\t\t}
\t}
};

/**
 * Function: decodeChildren
 * 
 * Decodes all children of the given node using <decodeChild>.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * node - XML node to be decoded.
 * obj - Objec to encode the node into.
 */\t
mxObjectCodec.prototype.decodeChildren = function(dec, node, obj)
{
\tvar child = node.firstChild;
\t
\twhile (child != null)
\t{
\t\tvar tmp = child.nextSibling;
\t\t
\t\tif (child.nodeType == mxConstants.NODETYPE_ELEMENT &&
\t\t\t!this.processInclude(dec, child, obj))
\t\t{
\t\t\tthis.decodeChild(dec, child, obj);
\t\t}
\t\t
\t\tchild = tmp;
\t}
};

/**
 * Function: decodeChild
 * 
 * Reads the specified child into the given object.
 * 
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * child - XML child element to be decoded.
 * obj - Objec to encode the node into.
 */\t
mxObjectCodec.prototype.decodeChild = function(dec, child, obj)
{
\tvar fieldname = this.getFieldName(child.getAttribute('as'));
\t
\tif (fieldname == null || !this.isExcluded(obj, fieldname, child, false))
\t{
\t\tvar template = this.getFieldTemplate(obj, fieldname, child);
\t\tvar value = null;
\t\t
\t\tif (child.nodeName == 'add')
\t\t{
\t\t\tvalue = child.getAttribute('value');
\t\t\t
\t\t\tif (value == null && mxObjectCodec.allowEval)
\t\t\t{
\t\t\t\tvalue = mxUtils.eval(mxUtils.getTextContent(child));
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvalue = dec.decode(child, template);
\t\t}

\t\ttry
\t\t{
\t\t\tthis.addObjectValue(obj, fieldname, value, template);
\t\t}
\t\tcatch (e)
\t\t{
\t\t\tthrow new Error(e.message + ' for ' + child.nodeName);
\t\t}
\t}
};

/**
 * Function: getFieldTemplate
 * 
 * Returns the template instance for the given field. This returns the
 * value of the field, null if the value is an array or an empty collection
 * if the value is a collection. The value is then used to populate the
 * field for a new instance. For strongly typed languages it may be
 * required to override this to return the correct collection instance
 * based on the encoded child.
 */\t
mxObjectCodec.prototype.getFieldTemplate = function(obj, fieldname, child)
{
\tvar template = obj[fieldname];
\t
\t// Non-empty arrays are replaced completely
    if (template instanceof Array && template.length > 0)
    {
        template = null;
    }
    
    return template;
};

/**
 * Function: addObjectValue
 * 
 * Sets the decoded child node as a value of the given object. If the
 * object is a map, then the value is added with the given fieldname as a
 * key. If the fieldname is not empty, then setFieldValue is called or
 * else, if the object is a collection, the value is added to the
 * collection. For strongly typed languages it may be required to
 * override this with the correct code to add an entry to an object.
 */\t
mxObjectCodec.prototype.addObjectValue = function(obj, fieldname, value, template)
{
\tif (value != null && value != template)
\t{
\t\tif (fieldname != null && fieldname.length > 0)
\t\t{
\t\t\tobj[fieldname] = value;
\t\t}
\t\telse
\t\t{
\t\t\tobj.push(value);
\t\t}
\t\t//mxLog.debug('Decoded '+mxUtils.getFunctionName(obj.constructor)+'.'+fieldname+': '+value);
\t}
};

/**
 * Function: processInclude
 *
 * Returns true if the given node is an include directive and
 * executes the include by decoding the XML document. Returns
 * false if the given node is not an include directive.
 *
 * Parameters:
 *
 * dec - <mxCodec> that controls the encoding/decoding process.
 * node - XML node to be checked.
 * into - Optional object to pass-thru to the codec.
 */
mxObjectCodec.prototype.processInclude = function(dec, node, into)
{
\tif (node.nodeName == 'include')
\t{
\t\tvar name = node.getAttribute('name');
\t\t
\t\tif (name != null)
\t\t{
\t\t\ttry
\t\t\t{
\t\t\t\tvar xml = mxUtils.load(name).getDocumentElement();
\t\t\t\t
\t\t\t\tif (xml != null)
\t\t\t\t{
\t\t\t\t\tdec.decode(xml, into);
\t\t\t\t}
\t\t\t}
\t\t\tcatch (e)
\t\t\t{
\t\t\t\t// ignore
\t\t\t}
\t\t}
\t\t
\t\treturn true;
\t}
\t
\treturn false;
};

/**
 * Function: beforeDecode
 *
 * Hook for subclassers to pre-process the node for
 * the specified object and return the node to be
 * used for further processing by <decode>.
 * The object is created based on the template in the 
 * calling method and is never null. This implementation
 * returns the input node. The return value of this
 * function is used in <decode> to perform
 * the default decoding into the given object.
 *
 * Parameters:
 *
 * dec - <mxCodec> that controls the decoding process.
 * node - XML node to be decoded.
 * obj - Object to encode the node into.
 */
mxObjectCodec.prototype.beforeDecode = function(dec, node, obj)
{
\treturn node;
};

/**
 * Function: afterDecode
 *
 * Hook for subclassers to post-process the object after
 * decoding. This implementation returns the given object
 * without any changes. The return value of this method
 * is returned to the decoder from <decode>.
 *
 * Parameters:
 *
 * enc - <mxCodec> that controls the encoding process.
 * node - XML node to be decoded.
 * obj - Object that represents the default decoding.
 */
mxObjectCodec.prototype.afterDecode = function(dec, node, obj)
{
\treturn obj;
};
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxCellCodec
\t *
\t * Codec for <mxCell>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec>
\t * and the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - children
\t * - edges
\t * - overlays
\t * - mxTransient
\t *
\t * Reference Fields:
\t *
\t * - parent
\t * - source
\t * - target
\t * 
\t * Transient fields can be added using the following code:
\t * 
\t * mxCodecRegistry.getCodec(mxCell).exclude.push('name_of_field');
\t * 
\t * To subclass <mxCell>, replace the template and add an alias as
\t * follows.
\t * 
\t * (code)
\t * function CustomCell(value, geometry, style)
\t * {
\t *   mxCell.apply(this, arguments);
\t * }
\t * 
\t * mxUtils.extend(CustomCell, mxCell);
\t * 
\t * mxCodecRegistry.getCodec(mxCell).template = new CustomCell();
\t * mxCodecRegistry.addAlias('CustomCell', 'mxCell');
\t * (end)
\t */
\tvar codec = new mxObjectCodec(new mxCell(),
\t\t['children', 'edges', 'overlays', 'mxTransient'],
\t\t['parent', 'source', 'target']);

\t/**
\t * Function: isCellCodec
\t *
\t * Returns true since this is a cell codec.
\t */
\tcodec.isCellCodec = function()
\t{
\t\treturn true;
\t};

\t/**
\t * Overidden to disable conversion of value to number.
\t */
\tcodec.isNumericAttribute = function(dec, attr, obj)
\t{
\t\treturn attr.nodeName !== 'value' && mxObjectCodec.prototype.isNumericAttribute.apply(this, arguments);
\t};
\t
\t/**
\t * Function: isExcluded
\t *
\t * Excludes user objects that are XML nodes.
\t */ 
\tcodec.isExcluded = function(obj, attr, value, isWrite)
\t{
\t\treturn mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
\t\t\t(isWrite && attr == 'value' &&
\t\t\tvalue.nodeType == mxConstants.NODETYPE_ELEMENT);
\t};
\t
\t/**
\t * Function: afterEncode
\t *
\t * Encodes an <mxCell> and wraps the XML up inside the
\t * XML of the user object (inversion).
\t */
\tcodec.afterEncode = function(enc, obj, node)
\t{
\t\tif (obj.value != null && obj.value.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t{
\t\t\t// Wraps the graphical annotation up in the user object (inversion)
\t\t\t// by putting the result of the default encoding into a clone of the
\t\t\t// user object (node type 1) and returning this cloned user object.
\t\t\tvar tmp = node;
\t\t\tnode = mxUtils.importNode(enc.document, obj.value, true);
\t\t\tnode.appendChild(tmp);
\t\t\t
\t\t\t// Moves the id attribute to the outermost XML node, namely the
\t\t\t// node which denotes the object boundaries in the file.
\t\t\tvar id = tmp.getAttribute('id');
\t\t\tnode.setAttribute('id', id);
\t\t\ttmp.removeAttribute('id');
\t\t}

\t\treturn node;
\t};

\t/**
\t * Function: beforeDecode
\t *
\t * Decodes an <mxCell> and uses the enclosing XML node as
\t * the user object for the cell (inversion).
\t */
\tcodec.beforeDecode = function(dec, node, obj)
\t{
\t\tvar inner = node.cloneNode(true);
\t\tvar classname = this.getName();
\t\t
\t\tif (node.nodeName != classname)
\t\t{
\t\t\t// Passes the inner graphical annotation node to the
\t\t\t// object codec for further processing of the cell.
\t\t\tvar tmp = node.getElementsByTagName(classname)[0];
\t\t\t
\t\t\tif (tmp != null && tmp.parentNode == node)
\t\t\t{
\t\t\t\tmxUtils.removeWhitespace(tmp, true);
\t\t\t\tmxUtils.removeWhitespace(tmp, false);
\t\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\t\tinner = tmp;
\t\t\t}
\t\t\telse
\t\t\t{
\t\t\t\tinner = null;
\t\t\t}
\t\t\t
\t\t\t// Creates the user object out of the XML node
\t\t\tobj.value = node.cloneNode(true);
\t\t\tvar id = obj.value.getAttribute('id');
\t\t\t
\t\t\tif (id != null)
\t\t\t{
\t\t\t\tobj.setId(id);
\t\t\t\tobj.value.removeAttribute('id');
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\t// Uses ID from XML file as ID for cell in model
\t\t\tobj.setId(node.getAttribute('id'));
\t\t}
\t\t\t
\t\t// Preprocesses and removes all Id-references in order to use the
\t\t// correct encoder (this) for the known references to cells (all).
\t\tif (inner != null)
\t\t{
\t\t\tfor (var i = 0; i < this.idrefs.length; i++)
\t\t\t{
\t\t\t\tvar attr = this.idrefs[i];
\t\t\t\tvar ref = inner.getAttribute(attr);
\t\t\t\t
\t\t\t\tif (ref != null)
\t\t\t\t{
\t\t\t\t\tinner.removeAttribute(attr);
\t\t\t\t\tvar object = dec.objects[ref] || dec.lookup(ref);
\t\t\t\t\t
\t\t\t\t\tif (object == null)
\t\t\t\t\t{
\t\t\t\t\t\t// Needs to decode forward reference
\t\t\t\t\t\tvar element = dec.getElementById(ref);
\t\t\t\t\t\t
\t\t\t\t\t\tif (element != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar decoder = mxCodecRegistry.codecs[element.nodeName] || this;
\t\t\t\t\t\t\tobject = decoder.decode(dec, element);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tobj[attr] = object;
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn inner;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxModelCodec
\t *
\t * Codec for <mxGraphModel>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec>
\t * and the <mxCodecRegistry>.
\t */
\tvar codec = new mxObjectCodec(new mxGraphModel());

\t/**
\t * Function: encodeObject
\t *
\t * Encodes the given <mxGraphModel> by writing a (flat) XML sequence of
\t * cell nodes as produced by the <mxCellCodec>. The sequence is
\t * wrapped-up in a node with the name root.
\t */
\tcodec.encodeObject = function(enc, obj, node)
\t{
\t\tvar rootNode = enc.document.createElement('root');
\t\tenc.encodeCell(obj.getRoot(), rootNode);
\t\tnode.appendChild(rootNode);
\t};

\t/**
\t * Function: decodeChild
\t * 
\t * Overrides decode child to handle special child nodes.
\t */\t
\tcodec.decodeChild = function(dec, child, obj)
\t{
\t\tif (child.nodeName == 'root')
\t\t{
\t\t\tthis.decodeRoot(dec, child, obj);
\t\t}
\t\telse
\t\t{
\t\t\tmxObjectCodec.prototype.decodeChild.apply(this, arguments);
\t\t}
\t};

\t/**
\t * Function: decodeRoot
\t *
\t * Reads the cells into the graph model. All cells
\t * are children of the root element in the node.
\t */
\tcodec.decodeRoot = function(dec, root, model)
\t{
\t\tvar rootCell = null;
\t\tvar tmp = root.firstChild;
\t\t
\t\twhile (tmp != null)
\t\t{
\t\t\tvar cell = dec.decodeCell(tmp);
\t\t\t
\t\t\tif (cell != null && cell.getParent() == null)
\t\t\t{
\t\t\t\trootCell = cell;
\t\t\t}
\t\t\t
\t\t\ttmp = tmp.nextSibling;
\t\t}

\t\t// Sets the root on the model if one has been decoded
\t\tif (rootCell != null)
\t\t{
\t\t\tmodel.setRoot(rootCell);
\t\t}
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxRootChangeCodec
\t *
\t * Codec for <mxRootChange>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec> and
\t * the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - model
\t * - previous
\t * - root
\t */
\tvar codec = new mxObjectCodec(new mxRootChange(),
\t\t['model', 'previous', 'root']);

\t/**
\t * Function: onEncode
\t *
\t * Encodes the child recursively.
\t */
\tcodec.afterEncode = function(enc, obj, node)
\t{
\t\tenc.encodeCell(obj.root, node);
\t\t
\t\treturn node;
\t};

\t/**
\t * Function: beforeDecode
\t *
\t * Decodes the optional children as cells
\t * using the respective decoder.
\t */
\tcodec.beforeDecode = function(dec, node, obj)
\t{
\t\tif (node.firstChild != null &&
\t\t\tnode.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t{
\t\t\t// Makes sure the original node isn't modified
\t\t\tnode = node.cloneNode(true);
\t\t\t
\t\t\tvar tmp = node.firstChild;
\t\t\tobj.root = dec.decodeCell(tmp, false);

\t\t\tvar tmp2 = tmp.nextSibling;
\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\ttmp = tmp2;
\t\t
\t\t\twhile (tmp != null)
\t\t\t{
\t\t\t\ttmp2 = tmp.nextSibling;
\t\t\t\tdec.decodeCell(tmp);
\t\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\t\ttmp = tmp2;
\t\t\t}
\t\t}
\t\t
\t\treturn node;
\t};
\t
\t/**
\t * Function: afterDecode
\t *
\t * Restores the state by assigning the previous value.
\t */
\tcodec.afterDecode = function(dec, node, obj)
\t{
\t\tobj.previous = obj.root;
\t\t
\t\treturn obj;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxChildChangeCodec
\t *
\t * Codec for <mxChildChange>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec> and
\t * the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - model
\t * - previous
\t * - previousIndex
\t * - child
\t *
\t * Reference Fields:
\t *
\t * - parent
\t */
\tvar codec = new mxObjectCodec(new mxChildChange(),
\t\t['model', 'child', 'previousIndex'],
\t\t['parent', 'previous']);

\t/**
\t * Function: isReference
\t *
\t * Returns true for the child attribute if the child
\t * cell had a previous parent or if we're reading the
\t * child as an attribute rather than a child node, in
\t * which case it's always a reference.
\t */
\tcodec.isReference = function(obj, attr, value, isWrite)
\t{
\t\tif (attr == 'child' && (!isWrite || obj.model.contains(obj.previous)))
\t\t{
\t\t\treturn true;
\t\t}
\t\t
\t\treturn mxUtils.indexOf(this.idrefs, attr) >= 0;
\t};

\t/**
\t * Function: isExcluded
\t *
\t * Excludes references to parent or previous if not in the model.
\t */
  \tcodec.isExcluded = function(obj, attr, value, write)
  \t{
  \t\treturn mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
  \t\t\t(write && value != null && (attr == 'previous' ||
  \t\t\tattr == 'parent') && !obj.model.contains(value));
  \t};
  \t
\t/**
\t * Function: afterEncode
\t *
\t * Encodes the child recusively and adds the result
\t * to the given node.
\t */
\tcodec.afterEncode = function(enc, obj, node)
\t{
\t\tif (this.isReference(obj, 'child', obj.child, true))
\t\t{
\t\t\t// Encodes as reference (id)
\t\t\tnode.setAttribute('child', enc.getId(obj.child));
\t\t}
\t\telse
\t\t{
\t\t\t// At this point, the encoder is no longer able to know which cells
\t\t\t// are new, so we have to encode the complete cell hierarchy and
\t\t\t// ignore the ones that are already there at decoding time. Note:
\t\t\t// This can only be resolved by moving the notify event into the
\t\t\t// execute of the edit.
\t\t\tenc.encodeCell(obj.child, node);
\t\t}
\t\t
\t\treturn node;
\t};

\t/**
\t * Function: beforeDecode
\t *
\t * Decodes the any child nodes as using the respective
\t * codec from the registry.
\t */
\tcodec.beforeDecode = function(dec, node, obj)
\t{
\t\tif (node.firstChild != null &&
\t\t\tnode.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t{
\t\t\t// Makes sure the original node isn't modified
\t\t\tnode = node.cloneNode(true);
\t\t\t
\t\t\tvar tmp = node.firstChild;
\t\t\tobj.child = dec.decodeCell(tmp, false);

\t\t\tvar tmp2 = tmp.nextSibling;
\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\ttmp = tmp2;
\t\t\t
\t\t\twhile (tmp != null)
\t\t\t{
\t\t\t\ttmp2 = tmp.nextSibling;
\t\t\t\t
\t\t\t\tif (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t\t{
\t\t\t\t\t// Ignores all existing cells because those do not need to
\t\t\t\t\t// be re-inserted into the model. Since the encoded version
\t\t\t\t\t// of these cells contains the new parent, this would leave
\t\t\t\t\t// to an inconsistent state on the model (ie. a parent
\t\t\t\t\t// change without a call to parentForCellChanged).
\t\t\t\t\tvar id = tmp.getAttribute('id');
\t\t\t\t\t
\t\t\t\t\tif (dec.lookup(id) == null)
\t\t\t\t\t{
\t\t\t\t\t\tdec.decodeCell(tmp);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\ttmp.parentNode.removeChild(tmp);
\t\t\t\ttmp = tmp2;
\t\t\t}
\t\t}
\t\telse
\t\t{
\t\t\tvar childRef = node.getAttribute('child');
\t\t\tobj.child = dec.getObject(childRef);
\t\t}
\t\t
\t\treturn node;
\t};
\t
\t/**
\t * Function: afterDecode
\t *
\t * Restores object state in the child change.
\t */
\tcodec.afterDecode = function(dec, node, obj)
\t{
\t\t// Cells are decoded here after a complete transaction so the previous
\t\t// parent must be restored on the cell for the case where the cell was
\t\t// added. This is needed for the local model to identify the cell as a
\t\t// new cell and register the ID.
        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;
        }

\t\treturn obj;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxTerminalChangeCodec
\t *
\t * Codec for <mxTerminalChange>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec> and
\t * the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - model
\t * - previous
\t *
\t * Reference Fields:
\t *
\t * - cell
\t * - terminal
\t */
\tvar codec = new mxObjectCodec(new mxTerminalChange(),
\t\t['model', 'previous'], ['cell', 'terminal']);

\t/**
\t * Function: afterDecode
\t *
\t * Restores the state by assigning the previous value.
\t */
\tcodec.afterDecode = function(dec, node, obj)
\t{
\t\tobj.previous = obj.terminal;
\t\t
\t\treturn obj;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxGenericChangeCodec
 *
 * Codec for <mxValueChange>s, <mxStyleChange>s, <mxGeometryChange>s,
 * <mxCollapseChange>s and <mxVisibleChange>s. This class is created
 * and registered dynamically at load time and used implicitly
 * via <mxCodec> and the <mxCodecRegistry>.
 *
 * Transient Fields:
 *
 * - model
 * - previous
 *
 * Reference Fields:
 *
 * - cell
 * 
 * Constructor: mxGenericChangeCodec
 *
 * Factory function that creates a <mxObjectCodec> for
 * the specified change and fieldname.
 *
 * Parameters:
 *
 * obj - An instance of the change object.
 * variable - The fieldname for the change data.
 */
var mxGenericChangeCodec = function(obj, variable)
{
\tvar codec = new mxObjectCodec(obj,  ['model', 'previous'], ['cell']);

\t/**
\t * Function: afterDecode
\t *
\t * Restores the state by assigning the previous value.
\t */
\tcodec.afterDecode = function(dec, node, obj)
\t{
\t\t// Allows forward references in sessions. This is a workaround
\t\t// for the sequence of edits in mxGraph.moveCells and cellsAdded.
\t\tif (mxUtils.isNode(obj.cell))
\t\t{
\t\t\tobj.cell = dec.decodeCell(obj.cell, false);
\t\t}

\t\tobj.previous = obj[variable];

\t\treturn obj;
\t};
\t
\treturn codec;
};

// Registers the codecs
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'));
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxGraphCodec
\t *
\t * Codec for <mxGraph>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec>
\t * and the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - graphListeners
\t * - eventListeners
\t * - view
\t * - container
\t * - cellRenderer
\t * - editor
\t * - selection
\t */
\treturn new mxObjectCodec(new mxGraph(),
\t\t['graphListeners', 'eventListeners', 'view', 'container',
\t\t'cellRenderer', 'editor', 'selection']);

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxGraphViewCodec
\t *
\t * Custom encoder for <mxGraphView>s. This class is created
\t * and registered dynamically at load time and used implicitly via
\t * <mxCodec> and the <mxCodecRegistry>. This codec only writes views
\t * into a XML format that can be used to create an image for
\t * the graph, that is, it contains absolute coordinates with
\t * computed perimeters, edge styles and cell styles.
\t */
\tvar codec = new mxObjectCodec(new mxGraphView());

\t/**
\t * Function: encode
\t *
\t * Encodes the given <mxGraphView> using <encodeCell>
\t * starting at the model's root. This returns the
\t * top-level graph node of the recursive encoding.
\t */
\tcodec.encode = function(enc, view)
\t{
\t\treturn this.encodeCell(enc, view,
\t\t\tview.graph.getModel().getRoot());
\t};

\t/**
\t * Function: encodeCell
\t *
\t * Recursively encodes the specifed cell. Uses layer
\t * as the default nodename. If the cell's parent is
\t * null, then graph is used for the nodename. If
\t * <mxGraphModel.isEdge> returns true for the cell,
\t * then edge is used for the nodename, else if
\t * <mxGraphModel.isVertex> returns true for the cell,
\t * then vertex is used for the nodename.
\t *
\t * <mxGraph.getLabel> is used to create the label
\t * attribute for the cell. For graph nodes and vertices
\t * the bounds are encoded into x, y, width and height.
\t * For edges the points are encoded into a points
\t * attribute as a space-separated list of comma-separated
\t * coordinate pairs (eg. x0,y0 x1,y1 ... xn,yn). All
\t * values from the cell style are added as attribute
\t * values to the node. 
\t */
\tcodec.encodeCell = function(enc, view, cell)
\t{
\t\tvar model = view.graph.getModel();
\t\tvar state = view.getState(cell);
\t\tvar parent = model.getParent(cell);
\t\t
\t\tif (parent == null || state != null)
\t\t{
\t\t\tvar childCount = model.getChildCount(cell);
\t\t\tvar geo = view.graph.getCellGeometry(cell);
\t\t\tvar name = null;
\t\t\t
\t\t\tif (parent == model.getRoot())
\t\t\t{
\t\t\t\tname = 'layer';
\t\t\t}
\t\t\telse if (parent == null)
\t\t\t{
\t\t\t\tname = 'graph';
\t\t\t}
\t\t\telse if (model.isEdge(cell))
\t\t\t{
\t\t\t\tname = 'edge';
\t\t\t}
\t\t\telse if (childCount > 0 && geo != null)
\t\t\t{
\t\t\t\tname = 'group';
\t\t\t}
\t\t\telse if (model.isVertex(cell))
\t\t\t{
\t\t\t\tname = 'vertex';
\t\t\t}
\t\t\t
\t\t\tif (name != null)
\t\t\t{
\t\t\t\tvar node = enc.document.createElement(name);
\t\t\t\tvar lab = view.graph.getLabel(cell);
\t\t\t\t
\t\t\t\tif (lab != null)
\t\t\t\t{
\t\t\t\t\tnode.setAttribute('label', view.graph.getLabel(cell));
\t\t\t\t\t
\t\t\t\t\tif (view.graph.isHtmlLabel(cell))
\t\t\t\t\t{
\t\t\t\t\t\tnode.setAttribute('html', true);
\t\t\t\t\t}
\t\t\t\t}
\t\t
\t\t\t\tif (parent == null)
\t\t\t\t{
\t\t\t\t\tvar bounds = view.getGraphBounds();
\t\t\t\t\t
\t\t\t\t\tif (bounds != null)
\t\t\t\t\t{
\t\t\t\t\t\tnode.setAttribute('x', Math.round(bounds.x));
\t\t\t\t\t\tnode.setAttribute('y', Math.round(bounds.y));
\t\t\t\t\t\tnode.setAttribute('width', Math.round(bounds.width));
\t\t\t\t\t\tnode.setAttribute('height', Math.round(bounds.height));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tnode.setAttribute('scale', view.scale);
\t\t\t\t}
\t\t\t\telse if (state != null && geo != null)
\t\t\t\t{
\t\t\t\t\t// Writes each key, value in the style pair to an attribute
\t\t\t\t    for (var i in state.style)
\t\t\t\t    {
\t\t\t\t    \tvar value = state.style[i];
\t\t
\t\t\t\t    \t// Tries to turn objects and functions into strings
\t\t\t\t\t    if (typeof(value) == 'function' &&
\t\t\t\t\t\t\ttypeof(value) == 'object')
\t\t\t\t\t\t{
\t\t\t\t\t    \tvalue = mxStyleRegistry.getName(value);
\t\t\t\t        }
\t\t\t\t    \t
\t\t\t\t    \tif (value != null &&
\t\t\t\t    \t\ttypeof(value) != 'function' &&
\t\t\t\t\t\t\ttypeof(value) != 'object')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tnode.setAttribute(i, value);
\t\t\t\t        }
\t\t\t\t    }
\t\t\t\t    
\t\t\t\t\tvar abs = state.absolutePoints;
\t\t\t\t\t
\t\t\t\t\t// Writes the list of points into one attribute
\t\t\t\t\tif (abs != null && abs.length > 0)
\t\t\t\t\t{
\t\t\t\t\t\tvar pts = Math.round(abs[0].x) + ',' + Math.round(abs[0].y);
\t\t
\t\t\t\t\t\tfor (var i=1; i<abs.length; i++)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tpts += ' ' + Math.round(abs[i].x) + ',' +
\t\t\t\t\t\t\t\tMath.round(abs[i].y);
\t\t\t\t\t\t}
\t\t
\t\t\t\t\t\tnode.setAttribute('points', pts);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// Writes the bounds into 4 attributes
\t\t\t\t\telse
\t\t\t\t\t{
\t\t\t\t\t\tnode.setAttribute('x', Math.round(state.x));
\t\t\t\t\t\tnode.setAttribute('y', Math.round(state.y));
\t\t\t\t\t\tnode.setAttribute('width', Math.round(state.width));
\t\t\t\t\t\tnode.setAttribute('height', Math.round(state.height));\t\t\t\t
\t\t\t\t\t}
\t\t
\t\t\t\t\tvar offset = state.absoluteOffset;
\t\t\t\t\t
\t\t\t\t\t// Writes the offset into 2 attributes
\t\t\t\t\tif (offset != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (offset.x != 0)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tnode.setAttribute('dx', Math.round(offset.x));
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (offset.y != 0)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tnode.setAttribute('dy', Math.round(offset.y));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t
\t\t\t\tfor (var i=0; i<childCount; i++)
\t\t\t\t{
\t\t\t\t\tvar childNode = this.encodeCell(enc,
\t\t\t\t\t\t\tview, model.getChildAt(cell, i));
\t\t\t\t\t
\t\t\t\t\tif (childNode != null)
\t\t\t\t\t{
\t\t\t\t\t\tnode.appendChild(childNode);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\treturn node;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStylesheetCodec
 *
 * Codec for <mxStylesheet>s. This class is created and registered
 * dynamically at load time and used implicitly via <mxCodec>
 * and the <mxCodecRegistry>.
 */
var mxStylesheetCodec = mxCodecRegistry.register(function()
{
\tvar codec = new mxObjectCodec(new mxStylesheet());

\t/**
\t * Function: encode
\t *
\t * Encodes a stylesheet. See <decode> for a description of the
\t * format.
\t */
\tcodec.encode = function(enc, obj)
\t{
\t\tvar node = enc.document.createElement(this.getName());
\t\t
\t\tfor (var i in obj.styles)
\t\t{
\t\t\tvar style = obj.styles[i];
\t\t\tvar styleNode = enc.document.createElement('add');
\t\t\t
\t\t\tif (i != null)
\t\t\t{
\t\t\t\tstyleNode.setAttribute('as', i);
\t\t\t\t
\t\t\t\tfor (var j in style)
\t\t\t\t{
\t\t\t\t\tvar value = this.getStringValue(j, style[j]);
\t\t\t\t\t
\t\t\t\t\tif (value != null)
\t\t\t\t\t{
\t\t\t\t\t\tvar entry = enc.document.createElement('add');
\t\t\t\t\t\tentry.setAttribute('value', value);
\t\t\t\t\t\tentry.setAttribute('as', j);
\t\t\t\t\t\tstyleNode.appendChild(entry);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (styleNode.childNodes.length > 0)
\t\t\t\t{
\t\t\t\t\tnode.appendChild(styleNode);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t    return node;
\t};

\t/**
\t * Function: getStringValue
\t *
\t * Returns the string for encoding the given value.
\t */
\tcodec.getStringValue = function(key, value)
\t{
\t\tvar type = typeof(value);
\t\t
\t\tif (type == 'function')
\t\t{
\t\t\tvalue = mxStyleRegistry.getName(value);
\t\t}
\t\telse if (type == 'object')
\t\t{
\t\t\tvalue = null;
\t\t}
\t\t
\t\treturn value;
\t};
\t
\t/**
\t * Function: decode
\t *
\t * Reads a sequence of the following child nodes
\t * and attributes:
\t *
\t * Child Nodes:
\t *
\t * add - Adds a new style.
\t *
\t * Attributes:
\t *
\t * as - Name of the style.
\t * extend - Name of the style to inherit from.
\t *
\t * Each node contains another sequence of add and remove nodes with the following
\t * attributes:
\t *
\t * as - Name of the style (see <mxConstants>).
\t * value - Value for the style.
\t *
\t * Instead of the value-attribute, one can put Javascript expressions into
\t * the node as follows if <mxStylesheetCodec.allowEval> is true:
\t * <add as=\"perimeter\">mxPerimeter.RectanglePerimeter</add>
\t *
\t * A remove node will remove the entry with the name given in the as-attribute
\t * from the style.
\t * 
\t * Example:
\t *
\t * (code)
\t * <mxStylesheet as=\"stylesheet\">
\t *   <add as=\"text\">
\t *     <add as=\"fontSize\" value=\"12\"/>
\t *   </add>
\t *   <add as=\"defaultVertex\" extend=\"text\">
\t *     <add as=\"shape\" value=\"rectangle\"/>
\t *   </add>
\t * </mxStylesheet>
\t * (end)
\t */
\tcodec.decode = function(dec, node, into)
\t{
\t\tvar obj = into || new this.template.constructor();
\t\tvar id = node.getAttribute('id');
\t\t
\t\tif (id != null)
\t\t{
\t\t\tdec.objects[id] = obj;
\t\t}
\t\t
\t\tnode = node.firstChild;
\t\t
\t\twhile (node != null)
\t\t{
\t\t\tif (!this.processInclude(dec, node, obj) && node.nodeName == 'add')
\t\t\t{
\t\t\t\tvar as = node.getAttribute('as');
\t\t\t\t
\t\t\t\tif (as != null)
\t\t\t\t{
\t\t\t\t\tvar extend = node.getAttribute('extend');
\t\t\t\t\tvar style = (extend != null) ? mxUtils.clone(obj.styles[extend]) : null;
\t\t\t\t\t
\t\t\t\t\tif (style == null)
\t\t\t\t\t{
\t\t\t\t\t\tif (extend != null)
\t\t\t\t\t\t{
\t\t\t\t\t\t\tmxLog.warn('mxStylesheetCodec.decode: stylesheet ' +
\t\t\t\t\t\t\t\textend + ' not found to extend');
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tstyle = new Object();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tvar entry = node.firstChild;
\t\t\t\t\t
\t\t\t\t\twhile (entry != null)
\t\t\t\t\t{
\t\t\t\t\t\tif (entry.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t\t\t\t{
\t\t\t\t\t\t \tvar key = entry.getAttribute('as');
\t\t\t\t\t\t \t
\t\t\t\t\t\t \tif (entry.nodeName == 'add')
\t\t\t\t\t\t \t{
\t\t\t\t\t\t\t \tvar text = mxUtils.getTextContent(entry);
\t\t\t\t\t\t\t \tvar value = null;
\t\t\t\t\t\t\t \t
\t\t\t\t\t\t\t \tif (text != null && text.length > 0 && mxStylesheetCodec.allowEval)
\t\t\t\t\t\t\t \t{
\t\t\t\t\t\t\t \t\tvalue = mxUtils.eval(text);
\t\t\t\t\t\t\t \t}
\t\t\t\t\t\t\t \telse
\t\t\t\t\t\t\t \t{
\t\t\t\t\t\t\t \t\tvalue = entry.getAttribute('value');
\t\t\t\t\t\t\t \t\t
\t\t\t\t\t\t\t \t\tif (mxUtils.isNumeric(value))
\t\t\t\t\t\t\t \t\t{
\t\t\t\t\t\t\t\t\t\tvalue = parseFloat(value);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t \t}

\t\t\t\t\t\t\t \tif (value != null)
\t\t\t\t\t\t\t \t{
\t\t\t\t\t\t\t \t\tstyle[key] = value;
\t\t\t\t\t\t\t \t}
\t\t\t\t\t\t \t}
\t\t\t\t\t\t \telse if (entry.nodeName == 'remove')
\t\t\t\t\t\t \t{
\t\t\t\t\t\t \t\tdelete style[key];
\t\t\t\t\t\t \t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tentry = entry.nextSibling;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tobj.putCellStyle(as, style);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tnode = node.nextSibling;
\t\t}
\t\t
\t\treturn obj;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());

/**
 * Variable: allowEval
 * 
 * Static global switch that specifies if the use of eval is allowed for
 * evaluating text content. Default is true. Set this to false if stylesheets
 * may contain user input.
 */
mxStylesheetCodec.allowEval = true;
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxDefaultKeyHandlerCodec
\t *
\t * Custom codec for configuring <mxDefaultKeyHandler>s. This class is created
\t * and registered dynamically at load time and used implicitly via
\t * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
\t * data for existing key handlers, it does not encode or create key handlers.
\t */
\tvar codec = new mxObjectCodec(new mxDefaultKeyHandler());

\t/**
\t * Function: encode
\t *
\t * Returns null.
\t */
\tcodec.encode = function(enc, obj)
\t{
\t\treturn null;
\t};
\t
\t/**
\t * Function: decode
\t *
\t * Reads a sequence of the following child nodes
\t * and attributes:
\t *
\t * Child Nodes:
\t *
\t * add - Binds a keystroke to an actionname.
\t *
\t * Attributes:
\t *
\t * as - Keycode.
\t * action - Actionname to execute in editor.
\t * control - Optional boolean indicating if
\t * \t\tthe control key must be pressed.
\t *
\t * Example:
\t *
\t * (code)
\t * <mxDefaultKeyHandler as=\"keyHandler\">
\t *   <add as=\"88\" control=\"true\" action=\"cut\"/>
\t *   <add as=\"67\" control=\"true\" action=\"copy\"/>
\t *   <add as=\"86\" control=\"true\" action=\"paste\"/>
\t * </mxDefaultKeyHandler>
\t * (end)
\t *
\t * The keycodes are for the x, c and v keys.
\t *
\t * See also: <mxDefaultKeyHandler.bindAction>,
\t * http://www.js-examples.com/page/tutorials__key_codes.html
\t */
\tcodec.decode = function(dec, node, into)
\t{
\t\tif (into != null)
\t\t{
\t\t\tvar editor = into.editor;
\t\t\tnode = node.firstChild;
\t\t\t
\t\t\twhile (node != null)
\t\t\t{
\t\t\t\tif (!this.processInclude(dec, node, into) &&
\t\t\t\t\tnode.nodeName == 'add')
\t\t\t\t{
\t\t\t\t\tvar as = node.getAttribute('as');
\t\t\t\t\tvar action = node.getAttribute('action');
\t\t\t\t\tvar control = node.getAttribute('control');
\t\t\t\t\t
\t\t\t\t\tinto.bindAction(as, action, control);
\t\t\t\t}
\t\t\t\t
\t\t\t\tnode = node.nextSibling;
\t\t\t}
\t\t}
\t\t
\t\treturn into;
\t};

\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxDefaultToolbarCodec
 *
 * Custom codec for configuring <mxDefaultToolbar>s. This class is created
 * and registered dynamically at load time and used implicitly via
 * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
 * data for existing toolbars handlers, it does not encode or create toolbars.
 */
var mxDefaultToolbarCodec = mxCodecRegistry.register(function()
{
\tvar codec = new mxObjectCodec(new mxDefaultToolbar());

\t/**
\t * Function: encode
\t *
\t * Returns null.
\t */
\tcodec.encode = function(enc, obj)
\t{
\t\treturn null;
\t};
\t
\t/**
\t * Function: decode
\t *
\t * Reads a sequence of the following child nodes
\t * and attributes:
\t *
\t * Child Nodes:
\t *
\t * add - Adds a new item to the toolbar. See below for attributes.
\t * separator - Adds a vertical separator. No attributes.
\t * hr - Adds a horizontal separator. No attributes.
\t * br - Adds a linefeed. No attributes. 
\t *
\t * Attributes:
\t *
\t * as - Resource key for the label.
\t * action - Name of the action to execute in enclosing editor.
\t * mode - Modename (see below).
\t * template - Template name for cell insertion.
\t * style - Optional style to override the template style.
\t * icon - Icon (relative/absolute URL).
\t * pressedIcon - Optional icon for pressed state (relative/absolute URL).
\t * id - Optional ID to be used for the created DOM element.
\t * toggle - Optional 0 or 1 to disable toggling of the element. Default is
\t * 1 (true).
\t *
\t * The action, mode and template attributes are mutually exclusive. The
\t * style can only be used with the template attribute. The add node may
\t * contain another sequence of add nodes with as and action attributes
\t * to create a combo box in the toolbar. If the icon is specified then
\t * a list of the child node is expected to have its template attribute
\t * set and the action is ignored instead.
\t * 
\t * Nodes with a specified template may define a function to be used for
\t * inserting the cloned template into the graph. Here is an example of such
\t * a node:
\t * 
\t * (code)
\t * <add as=\"Swimlane\" template=\"swimlane\" icon=\"images/swimlane.gif\"><![CDATA[
\t *   function (editor, cell, evt, targetCell)
\t *   {
\t *     var pt = mxUtils.convertPoint(
\t *       editor.graph.container, mxEvent.getClientX(evt),
\t *         mxEvent.getClientY(evt));
\t *     return editor.addVertex(targetCell, cell, pt.x, pt.y);
\t *   }
\t * ]]></add>
\t * (end)
\t * 
\t * In the above function, editor is the enclosing <mxEditor> instance, cell
\t * is the clone of the template, evt is the mouse event that represents the
\t * drop and targetCell is the cell under the mousepointer where the drop
\t * occurred. The targetCell is retrieved using <mxGraph.getCellAt>.
\t *
\t * Futhermore, nodes with the mode attribute may define a function to
\t * be executed upon selection of the respective toolbar icon. In the
\t * example below, the default edge style is set when this specific
\t * connect-mode is activated:
\t *
\t * (code)
\t * <add as=\"connect\" mode=\"connect\"><![CDATA[
\t *   function (editor)
\t *   {
\t *     if (editor.defaultEdge != null)
\t *     {
\t *       editor.defaultEdge.style = 'straightEdge';
\t *     }
\t *   }
\t * ]]></add>
\t * (end)
\t * 
\t * Both functions require <mxDefaultToolbarCodec.allowEval> to be set to true.
\t *
\t * Modes:
\t *
\t * select - Left mouse button used for rubberband- & cell-selection.
\t * connect - Allows connecting vertices by inserting new edges.
\t * pan - Disables selection and switches to panning on the left button.
\t *
\t * Example:
\t *
\t * To add items to the toolbar:
\t * 
\t * (code)
\t * <mxDefaultToolbar as=\"toolbar\">
\t *   <add as=\"save\" action=\"save\" icon=\"images/save.gif\"/>
\t *   <br/><hr/>
\t *   <add as=\"select\" mode=\"select\" icon=\"images/select.gif\"/>
\t *   <add as=\"connect\" mode=\"connect\" icon=\"images/connect.gif\"/>
\t * </mxDefaultToolbar>
\t * (end)
\t */
\tcodec.decode = function(dec, node, into)
\t{
\t\tif (into != null)
\t\t{
\t\t\tvar editor = into.editor;
\t\t\tnode = node.firstChild;
\t\t\t
\t\t\twhile (node != null)
\t\t\t{
\t\t\t\tif (node.nodeType == mxConstants.NODETYPE_ELEMENT)
\t\t\t\t{
\t\t\t\t\tif (!this.processInclude(dec, node, into))
\t\t\t\t\t{
\t\t\t\t\t\tif (node.nodeName == 'separator')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tinto.addSeparator();
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (node.nodeName == 'br')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tinto.toolbar.addBreak();
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (node.nodeName == 'hr')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tinto.toolbar.addLine();
\t\t\t\t\t\t}
\t\t\t\t\t\telse if (node.nodeName == 'add')
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar as = node.getAttribute('as');
\t\t\t\t\t\t\tas = mxResources.get(as) || as;
\t\t\t\t\t\t\tvar icon = node.getAttribute('icon');
\t\t\t\t\t\t\tvar pressedIcon = node.getAttribute('pressedIcon');
\t\t\t\t\t\t\tvar action = node.getAttribute('action');
\t\t\t\t\t\t\tvar mode = node.getAttribute('mode');
\t\t\t\t\t\t\tvar template = node.getAttribute('template');
\t\t\t\t\t\t\tvar toggle = node.getAttribute('toggle') != '0';
\t\t\t\t\t\t\tvar text = mxUtils.getTextContent(node);
\t\t\t\t\t\t\tvar elt = null;

\t\t\t\t\t\t\tif (action != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\telt = into.addItem(as, icon, action, pressedIcon);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (mode != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar funct = (mxDefaultToolbarCodec.allowEval) ? mxUtils.eval(text) : null;
\t\t\t\t\t\t\t\telt = into.addMode(as, icon, mode, pressedIcon, funct);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (template != null || (text != null && text.length > 0))
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar cell = editor.templates[template];
\t\t\t\t\t\t\t\tvar style = node.getAttribute('style');
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (cell != null && style != null)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tcell = editor.graph.cloneCell(cell);
\t\t\t\t\t\t\t\t\tcell.setStyle(style);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tvar insertFunction = null;
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (text != null && text.length > 0 && mxDefaultToolbarCodec.allowEval)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tinsertFunction = mxUtils.eval(text);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\telt = into.addPrototype(as, icon, cell, pressedIcon, insertFunction, toggle);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar children = mxUtils.getChildNodes(node);
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (children.length > 0)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tif (icon == null)
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tvar combo = into.addActionCombo(as);
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\tfor (var i=0; i<children.length; i++)
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tvar child = children[i];
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\tif (child.nodeName == 'separator')
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tinto.addOption(combo, '---');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\telse if (child.nodeName == 'add')
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tvar lab = child.getAttribute('as');
\t\t\t\t\t\t\t\t\t\t\t\tvar act = child.getAttribute('action');
\t\t\t\t\t\t\t\t\t\t\t\tinto.addActionOption(combo, lab, act);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\tvar select = null;
\t\t\t\t\t\t\t\t\t\tvar create = function()
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tvar template = editor.templates[select.value];
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\tif (template != null)
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tvar clone = template.clone();
\t\t\t\t\t\t\t\t\t\t\t\tvar style = select.options[select.selectedIndex].cellStyle;
\t\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\t\tif (style != null)
\t\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\t\tclone.setStyle(style);
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\t\treturn clone;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\telse
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tmxLog.warn('Template '+template+' not found');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\treturn null;
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\tvar img = into.addPrototype(as, icon, create, null, null, toggle);
\t\t\t\t\t\t\t\t\t\tselect = into.addCombo();
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t// Selects the toolbar icon if a selection change
\t\t\t\t\t\t\t\t\t\t// is made in the corresponding combobox.
\t\t\t\t\t\t\t\t\t\tmxEvent.addListener(select, 'change', function()
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tinto.toolbar.selectMode(img, function(evt)
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tvar pt = mxUtils.convertPoint(editor.graph.container,
\t\t\t\t\t\t\t\t\t\t\t\t\tmxEvent.getClientX(evt), mxEvent.getClientY(evt));
\t\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\t\treturn editor.addVertex(null, funct(), pt.x, pt.y);
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\tinto.toolbar.noReset = false;
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t// Adds the entries to the combobox
\t\t\t\t\t\t\t\t\t\tfor (var i=0; i<children.length; i++)
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tvar child = children[i];
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\tif (child.nodeName == 'separator')
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tinto.addOption(select, '---');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\telse if (child.nodeName == 'add')
\t\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\t\tvar lab = child.getAttribute('as');
\t\t\t\t\t\t\t\t\t\t\t\tvar tmp = child.getAttribute('template');
\t\t\t\t\t\t\t\t\t\t\t\tvar option = into.addOption(select, lab, tmp || template);
\t\t\t\t\t\t\t\t\t\t\t\toption.cellStyle = child.getAttribute('style');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Assigns an ID to the created element to access it later.
\t\t\t\t\t\t\tif (elt != null)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar id = node.getAttribute('id');
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (id != null && id.length > 0)
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\telt.setAttribute('id', id);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tnode = node.nextSibling;
\t\t\t}
\t\t}
\t\t
\t\treturn into;
\t};
\t
\t// Returns the codec into the registry
\treturn codec;

}());

/**
 * Variable: allowEval
 * 
 * Static global switch that specifies if the use of eval is allowed for
 * evaluating text content. Default is true. Set this to false if stylesheets
 * may contain user input
 */
mxDefaultToolbarCodec.allowEval = true;
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxDefaultPopupMenuCodec
\t *
\t * Custom codec for configuring <mxDefaultPopupMenu>s. This class is created
\t * and registered dynamically at load time and used implicitly via
\t * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
\t * data for existing popup menus, it does not encode or create menus. Note
\t * that this codec only passes the configuration node to the popup menu,
\t * which uses the config to dynamically create menus. See
\t * <mxDefaultPopupMenu.createMenu>.
\t */
\tvar codec = new mxObjectCodec(new mxDefaultPopupMenu());

\t/**
\t * Function: encode
\t *
\t * Returns null.
\t */
\tcodec.encode = function(enc, obj)
\t{
\t\treturn null;
\t};
\t
\t/**
\t * Function: decode
\t *
\t * Uses the given node as the config for <mxDefaultPopupMenu>.
\t */
\tcodec.decode = function(dec, node, into)
\t{
\t\tvar inc = node.getElementsByTagName('include')[0];
\t\t
\t\tif (inc != null)
\t\t{
\t\t\tthis.processInclude(dec, inc, into);
\t\t}
\t\telse if (into != null)
\t\t{
\t\t\tinto.config = node;
\t\t}
\t\t
\t\treturn into;
\t};
\t
\t// Returns the codec into the registry
\treturn codec;

}());
/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function()
{
\t/**
\t * Class: mxEditorCodec
\t *
\t * Codec for <mxEditor>s. This class is created and registered
\t * dynamically at load time and used implicitly via <mxCodec>
\t * and the <mxCodecRegistry>.
\t *
\t * Transient Fields:
\t *
\t * - modified
\t * - lastSnapshot
\t * - ignoredChanges
\t * - undoManager
\t * - graphContainer
\t * - toolbarContainer
\t */
\tvar codec = new mxObjectCodec(new mxEditor(),
\t\t['modified', 'lastSnapshot', 'ignoredChanges',
\t\t'undoManager', 'graphContainer', 'toolbarContainer']);

\t/**
\t * Function: beforeDecode
\t *
\t * Decodes the ui-part of the configuration node by reading
\t * a sequence of the following child nodes and attributes
\t * and passes the control to the default decoding mechanism:
\t *
\t * Child Nodes:
\t *
\t * stylesheet - Adds a CSS stylesheet to the document.
\t * resource - Adds the basename of a resource bundle.
\t * add - Creates or configures a known UI element.
\t *
\t * These elements may appear in any order given that the
\t * graph UI element is added before the toolbar element
\t * (see Known Keys).
\t *
\t * Attributes:
\t *
\t * as - Key for the UI element (see below).
\t * element - ID for the element in the document.
\t * style - CSS style to be used for the element or window.
\t * x - X coordinate for the new window.
\t * y - Y coordinate for the new window.
\t * width - Width for the new window.
\t * height - Optional height for the new window.
\t * name - Name of the stylesheet (absolute/relative URL).
\t * basename - Basename of the resource bundle (see <mxResources>).
\t *
\t * The x, y, width and height attributes are used to create a new
\t * <mxWindow> if the element attribute is not specified in an add
\t * node. The name and basename are only used in the stylesheet and
\t * resource nodes, respectively.
\t *
\t * Known Keys:
\t *
\t * graph - Main graph element (see <mxEditor.setGraphContainer>).
\t * title - Title element (see <mxEditor.setTitleContainer>).
\t * toolbar - Toolbar element (see <mxEditor.setToolbarContainer>).
\t * status - Status bar element (see <mxEditor.setStatusContainer>).
\t *
\t * Example:
\t *
\t * (code)
\t * <ui>
\t *   <stylesheet name=\"css/process.css\"/>
\t *   <resource basename=\"resources/app\"/>
\t *   <add as=\"graph\" element=\"graph\"
\t *     style=\"left:70px;right:20px;top:20px;bottom:40px\"/>
\t *   <add as=\"status\" element=\"status\"/>
\t *   <add as=\"toolbar\" x=\"10\" y=\"20\" width=\"54\"/>
\t * </ui>
\t * (end)
\t */
\tcodec.afterDecode = function(dec, node, obj)
\t{
\t\t// Assigns the specified templates for edges
\t\tvar defaultEdge = node.getAttribute('defaultEdge');
\t\t
\t\tif (defaultEdge != null)
\t\t{
\t\t\tnode.removeAttribute('defaultEdge');
\t\t\tobj.defaultEdge = obj.templates[defaultEdge];
\t\t}

\t\t// Assigns the specified templates for groups
\t\tvar defaultGroup = node.getAttribute('defaultGroup');
\t\t
\t\tif (defaultGroup != null)
\t\t{
\t\t\tnode.removeAttribute('defaultGroup');
\t\t\tobj.defaultGroup = obj.templates[defaultGroup];
\t\t}

\t\treturn obj;
\t};
\t
\t/**
\t * Function: decodeChild
\t * 
\t * Overrides decode child to handle special child nodes.
\t */\t
\tcodec.decodeChild = function(dec, child, obj)
\t{
\t\tif (child.nodeName == 'Array')
\t\t{
\t\t\tvar role = child.getAttribute('as');
\t\t\t
\t\t\tif (role == 'templates')
\t\t\t{
\t\t\t\tthis.decodeTemplates(dec, child, obj);
\t\t\t\treturn;
\t\t\t}
\t\t}
\t\telse if (child.nodeName == 'ui')
\t\t{
\t\t\tthis.decodeUi(dec, child, obj);
\t\t\treturn;
\t\t}
\t\t
\t\tmxObjectCodec.prototype.decodeChild.apply(this, arguments);
\t};
\t\t
\t/**
\t * Function: decodeUi
\t *
\t * Decodes the ui elements from the given node.
\t */
\tcodec.decodeUi = function(dec, node, editor)
\t{
\t\tvar tmp = node.firstChild;
\t\twhile (tmp != null)
\t\t{
\t\t\tif (tmp.nodeName == 'add')
\t\t\t{
\t\t\t\tvar as = tmp.getAttribute('as');
\t\t\t\tvar elt = tmp.getAttribute('element');
\t\t\t\tvar style = tmp.getAttribute('style');
\t\t\t\tvar element = null;

\t\t\t\tif (elt != null)
\t\t\t\t{
\t\t\t\t\telement = document.getElementById(elt);
\t\t\t\t\t
\t\t\t\t\tif (element != null && style != null)
\t\t\t\t\t{
\t\t\t\t\t\telement.style.cssText += ';' + style;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar x = parseInt(tmp.getAttribute('x'));
\t\t\t\t\tvar y = parseInt(tmp.getAttribute('y'));
\t\t\t\t\tvar width = tmp.getAttribute('width');
\t\t\t\t\tvar height = tmp.getAttribute('height');

\t\t\t\t\t// Creates a new window around the element
\t\t\t\t\telement = document.createElement('div');
\t\t\t\t\telement.style.cssText = style;
\t\t\t\t\t
\t\t\t\t\tvar wnd = new mxWindow(mxResources.get(as) || as,
\t\t\t\t\t\telement, x, y, width, height, false, true);
\t\t\t\t\twnd.setVisible(true);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// TODO: Make more generic
\t\t\t\tif (as == 'graph')
\t\t\t\t{
\t\t\t\t\teditor.setGraphContainer(element);
\t\t\t\t}
\t\t\t\telse if (as == 'toolbar')
\t\t\t\t{
\t\t\t\t\teditor.setToolbarContainer(element);
\t\t\t\t}
\t\t\t\telse if (as == 'title')
\t\t\t\t{
\t\t\t\t\teditor.setTitleContainer(element);
\t\t\t\t}
\t\t\t\telse if (as == 'status')
\t\t\t\t{
\t\t\t\t\teditor.setStatusContainer(element);
\t\t\t\t}
\t\t\t\telse if (as == 'map')
\t\t\t\t{
\t\t\t\t\teditor.setMapContainer(element);
\t\t\t\t}
\t\t\t}
\t\t\telse if (tmp.nodeName == 'resource')
\t\t\t{
\t\t\t\tmxResources.add(tmp.getAttribute('basename'));
\t\t\t}
\t\t\telse if (tmp.nodeName == 'stylesheet')
\t\t\t{
\t\t\t\tmxClient.link('stylesheet', tmp.getAttribute('name'));
\t\t\t}
\t\t\t
\t\t\ttmp = tmp.nextSibling;
\t\t}\t
\t};
\t
\t/**
\t * Function: decodeTemplates
\t *
\t * Decodes the cells from the given node as templates.
\t */
\tcodec.decodeTemplates = function(dec, node, editor)
\t{
\t\tif (editor.templates == null)
\t\t{
\t\t\teditor.templates = [];
\t\t}
\t\t
\t\tvar children = mxUtils.getChildNodes(node);
\t\tfor (var j=0; j<children.length; j++)
\t\t{
\t\t\tvar name = children[j].getAttribute('as');
\t\t\tvar child = children[j].firstChild;
\t\t\t
\t\t\twhile (child != null && child.nodeType != 1)
\t\t\t{
\t\t\t\tchild = child.nextSibling;
\t\t\t}
\t\t\t
\t\t\tif (child != null)
\t\t\t{
\t\t\t\t// LATER: Only single cells means you need
\t\t\t\t// to group multiple cells within another
\t\t\t\t// cell. This should be changed to support
\t\t\t\t// arrays of cells, or the wrapper must
\t\t\t\t// be automatically handled in this class.
\t\t\t\teditor.templates[name] = dec.decodeCell(child);
\t\t\t}
\t\t}
\t};
\t
\t// Returns the codec into the registry
\treturn codec;

}());
";
        yield from [];
    }

    /**
     * @codeCoverageIgnore
     */
    public function getTemplateName(): string
    {
        return "@UVDeskCoreFramework/mxClient.js";
    }

    /**
     * @codeCoverageIgnore
     */
    public function getDebugInfo(): array
    {
        return array (  42 => 1,);
    }

    public function getSourceContext(): Source
    {
        return new Source("", "@UVDeskCoreFramework/mxClient.js", "/home/bmdranzo/public_html/vendor/uvdesk/core-framework/Resources/views/mxClient.js");
    }
}
