/**
 * Copyright (c) 2006-2012, JGraph Holdings Ltd
 */
/**
 * Editor constructor executed on page load.
 */
Editor = function(chromeless, themes, model, graph, editable)
{
	mxEventSource.call(this);
	this.chromeless = (chromeless != null) ? chromeless : this.chromeless;
	this.initStencilRegistry();
	this.graph = graph || this.createGraph(themes, model);
	this.editable = (editable != null) ? editable : !chromeless;
	this.undoManager = this.createUndoManager();
	this.status = '';

	this.getOrCreateFilename = function()
	{
		return this.filename || mxResources.get('drawing', [Editor.pageCounter]) + '.xml';
	};
	
	this.getFilename = function()
	{
		return this.filename;
	};
	
	// Sets the status and fires a statusChanged event
	this.setStatus = function(value, fn)
	{
		this.status = value;
		this.statusFunction = fn;
		this.fireEvent(new mxEventObject('statusChanged'));
	};
	
	// Returns the current status
	this.getStatus = function()
	{
		return this.status;
	};

	// Updates modified state if graph changes
	this.graphChangeListener = function(sender, eventObject) 
	{
		var edit = (eventObject != null) ? eventObject.getProperty('edit') : null;
				
		if (edit == null || !edit.ignoreEdit)
		{
			this.setModified(true);
		}
	};
	
	this.graph.getModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
	{
		this.graphChangeListener.apply(this, arguments);
	}));

	// Sets persistent graph state defaults
	this.graph.resetViewOnRootChange = false;
	this.init();
};

/**
 * Measurements Units
 */
mxConstants.POINTS = 1;
mxConstants.MILLIMETERS = 2;
mxConstants.INCHES = 3;
mxConstants.METERS = 4;

/**
 * This ratio is with page scale 1
 */
mxConstants.PIXELS_PER_MM = 3.937;
mxConstants.PIXELS_PER_INCH = 100;

/**
 * Counts open editor tabs (must be global for cross-window access)
 */
Editor.pageCounter = 0;

// Cross-domain window access is not allowed in FF, so if we
// were opened from another domain then this will fail.
(function()
{
	try
	{
		var op = window;

		while (op.opener != null && typeof op.opener.Editor !== 'undefined' &&
			!isNaN(op.opener.Editor.pageCounter) &&	
			// Workaround for possible infinite loop in FF https://drawio.atlassian.net/browse/DS-795
			op.opener != op)
		{
			op = op.opener;
		}
		
		// Increments the counter in the first opener in the chain
		if (op != null)
		{
			op.Editor.pageCounter++;
			Editor.pageCounter = op.Editor.pageCounter;
		}
	}
	catch (e)
	{
		// ignore
	}
})();

/**
 * 
 */
Editor.defaultHtmlFont = '-apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI", system-ui, ui-sans-serif, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"';

/**
 * Specifies if local storage should be used (eg. on the iPad which has no filesystem)
 */
Editor.useLocalStorage = typeof(Storage) != 'undefined' && mxClient.IS_IOS;

/**
 * Window width for simple mode to collapse panels.
 */
Editor.smallScreenWidth = 1024;

/**
 * 
 */
Editor.helpImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDc4LTI0MHEyMSAwIDM1LjUtMTQuNVQ1MjgtMjkwcTAtMjEtMTQuNS0zNS41VDQ3OC0zNDBxLTIxIDAtMzUuNSAxNC41VDQyOC0yOTBxMCAyMSAxNC41IDM1LjVUNDc4LTI0MFptLTM2LTE1NGg3NHEwLTMzIDcuNS01MnQ0Mi41LTUycTI2LTI2IDQxLTQ5LjV0MTUtNTYuNXEwLTU2LTQxLTg2dC05Ny0zMHEtNTcgMC05Mi41IDMwVDM0Mi02MThsNjYgMjZxNS0xOCAyMi41LTM5dDUzLjUtMjFxMzIgMCA0OCAxNy41dDE2IDM4LjVxMCAyMC0xMiAzNy41VDUwNi01MjZxLTQ0IDM5LTU0IDU5dC0xMCA3M1ptMzggMzE0cS04MyAwLTE1Ni0zMS41VDE5Ny0xOTdxLTU0LTU0LTg1LjUtMTI3VDgwLTQ4MHEwLTgzIDMxLjUtMTU2VDE5Ny03NjNxNTQtNTQgMTI3LTg1LjVUNDgwLTg4MHE4MyAwIDE1NiAzMS41VDc2My03NjNxNTQgNTQgODUuNSAxMjdUODgwLTQ4MHEwIDgzLTMxLjUgMTU2VDc2My0xOTdxLTU0IDU0LTEyNyA4NS41VDQ4MC04MFptMC04MHExMzQgMCAyMjctOTN0OTMtMjI3cTAtMTM0LTkzLTIyN3QtMjI3LTkzcS0xMzQgMC0yMjcgOTN0LTkzIDIyN3EwIDEzNCA5MyAyMjd0MjI3IDkzWm0wLTMyMFoiLz48L3N2Zz4=';
Editor.menuImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTI0MHYtODBoNzIwdjgwSDEyMFptMC0yMDB2LTgwaDcyMHY4MEgxMjBabTAtMjAwdi04MGg3MjB2ODBIMTIwWiIvPjwvc3ZnPg==';
Editor.moveImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI4cHgiIGhlaWdodD0iMjhweCI+PGc+PC9nPjxnPjxnPjxnPjxwYXRoIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuNCwyLjQpc2NhbGUoMC44KXJvdGF0ZSg0NSwxMiwxMikiIHN0cm9rZT0iIzI5YjZmMiIgZmlsbD0iIzI5YjZmMiIgZD0iTTE1LDNsMi4zLDIuM2wtMi44OSwyLjg3bDEuNDIsMS40MkwxOC43LDYuN0wyMSw5VjNIMTV6IE0zLDlsMi4zLTIuM2wyLjg3LDIuODlsMS40Mi0xLjQyTDYuNyw1LjNMOSwzSDNWOXogTTksMjEgbC0yLjMtMi4zbDIuODktMi44N2wtMS40Mi0xLjQyTDUuMywxNy4zTDMsMTV2Nkg5eiBNMjEsMTVsLTIuMywyLjNsLTIuODctMi44OWwtMS40MiwxLjQybDIuODksMi44N0wxNSwyMWg2VjE1eiIvPjwvZz48L2c+PC9nPjwvc3ZnPgo=';
Editor.zoomInImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzg0LTEyMCA1MzItMzcycS0zMCAyNC02OSAzOHQtODMgMTRxLTEwOSAwLTE4NC41LTc1LjVUMTIwLTU4MHEwLTEwOSA3NS41LTE4NC41VDM4MC04NDBxMTA5IDAgMTg0LjUgNzUuNVQ2NDAtNTgwcTAgNDQtMTQgODN0LTM4IDY5bDI1MiAyNTItNTYgNTZaTTM4MC00MDBxNzUgMCAxMjcuNS01Mi41VDU2MC01ODBxMC03NS01Mi41LTEyNy41VDM4MC03NjBxLTc1IDAtMTI3LjUgNTIuNVQyMDAtNTgwcTAgNzUgNTIuNSAxMjcuNVQzODAtNDAwWm0tNDAtNjB2LTgwaC04MHYtODBoODB2LTgwaDgwdjgwaDgwdjgwaC04MHY4MGgtODBaIi8+PC9zdmc+';
Editor.zoomOutImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzg0LTEyMCA1MzItMzcycS0zMCAyNC02OSAzOHQtODMgMTRxLTEwOSAwLTE4NC41LTc1LjVUMTIwLTU4MHEwLTEwOSA3NS41LTE4NC41VDM4MC04NDBxMTA5IDAgMTg0LjUgNzUuNVQ2NDAtNTgwcTAgNDQtMTQgODN0LTM4IDY5bDI1MiAyNTItNTYgNTZaTTM4MC00MDBxNzUgMCAxMjcuNS01Mi41VDU2MC01ODBxMC03NS01Mi41LTEyNy41VDM4MC03NjBxLTc1IDAtMTI3LjUgNTIuNVQyMDAtNTgwcTAgNzUgNTIuNSAxMjcuNVQzODAtNDAwWk0yODAtNTQwdi04MGgyMDB2ODBIMjgwWiIvPjwvc3ZnPg==';
Editor.fullscreenImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtMjAwaDgwdjEyMGgxMjB2ODBIMTIwWm01MjAgMHYtODBoMTIwdi0xMjBoODB2MjAwSDY0MFpNMTIwLTY0MHYtMjAwaDIwMHY4MEgyMDB2MTIwaC04MFptNjQwIDB2LTEyMEg2NDB2LTgwaDIwMHYyMDBoLTgwWiIvPjwvc3ZnPg==';
Editor.fullscreenExitImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjQwLTEyMHYtMTIwSDEyMHYtODBoMjAwdjIwMGgtODBabTQwMCAwdi0yMDBoMjAwdjgwSDcyMHYxMjBoLTgwWk0xMjAtNjQwdi04MGgxMjB2LTEyMGg4MHYyMDBIMTIwWm01MjAgMHYtMjAwaDgwdjEyMGgxMjB2ODBINjQwWiIvPjwvc3ZnPg==';
Editor.zoomFitImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDgwLTMyMHEtNjYgMC0xMTMtNDd0LTQ3LTExM3EwLTY2IDQ3LTExM3QxMTMtNDdxNjYgMCAxMTMgNDd0NDcgMTEzcTAgNjYtNDcgMTEzdC0xMTMgNDdabTAtODBxMzMgMCA1Ni41LTIzLjVUNTYwLTQ4MHEwLTMzLTIzLjUtNTYuNVQ0ODAtNTYwcS0zMyAwLTU2LjUgMjMuNVQ0MDAtNDgwcTAgMzMgMjMuNSA1Ni41VDQ4MC00MDBabTAtODBaTTIwMC0xMjBxLTMzIDAtNTYuNS0yMy41VDEyMC0yMDB2LTE2MGg4MHYxNjBoMTYwdjgwSDIwMFptNDAwIDB2LTgwaDE2MHYtMTYwaDgwdjE2MHEwIDMzLTIzLjUgNTYuNVQ3NjAtMTIwSDYwMFpNMTIwLTYwMHYtMTYwcTAtMzMgMjMuNS01Ni41VDIwMC04NDBoMTYwdjgwSDIwMHYxNjBoLTgwWm02NDAgMHYtMTYwSDYwMHYtODBoMTYwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2MTYwaC04MFoiLz48L3N2Zz4=';
Editor.layersImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDgwLTExOCAxMjAtMzk4bDY2LTUwIDI5NCAyMjggMjk0LTIyOCA2NiA1MC0zNjAgMjgwWm0wLTIwMkwxMjAtNjAwbDM2MC0yODAgMzYwIDI4MC0zNjAgMjgwWm0wLTI4MFptMCAxNzggMjMwLTE3OC0yMzAtMTc4LTIzMCAxNzggMjMwIDE3OFoiLz48L3N2Zz4=';
Editor.editImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTIwMGg1N2wzOTEtMzkxLTU3LTU3LTM5MSAzOTF2NTdabS04MCA4MHYtMTcwbDUyOC01MjdxMTItMTEgMjYuNS0xN3QzMC41LTZxMTYgMCAzMSA2dDI2IDE4bDU1IDU2cTEyIDExIDE3LjUgMjZ0NS41IDMwcTAgMTYtNS41IDMwLjVUODE3LTY0N0wyOTAtMTIwSDEyMFptNjQwLTU4NC01Ni01NiA1NiA1NlptLTE0MSA4NS0yOC0yOSA1NyA1Ny0yOS0yOFoiLz48L3N2Zz4=';
Editor.duplicateImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzYwLTI0MHEtMzMgMC01Ni41LTIzLjVUMjgwLTMyMHYtNDgwcTAtMzMgMjMuNS01Ni41VDM2MC04ODBoMzYwcTMzIDAgNTYuNSAyMy41VDgwMC04MDB2NDgwcTAgMzMtMjMuNSA1Ni41VDcyMC0yNDBIMzYwWm0wLTgwaDM2MHYtNDgwSDM2MHY0ODBaTTIwMC04MHEtMzMgMC01Ni41LTIzLjVUMTIwLTE2MHYtNTYwaDgwdjU2MGg0NDB2ODBIMjAwWm0xNjAtMjQwdi00ODAgNDgwWiIvPjwvc3ZnPg==';
Editor.crossImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDYuNDFMMTcuNTkgNSAxMiAxMC41OSA2LjQxIDUgNSA2LjQxIDEwLjU5IDEyIDUgMTcuNTkgNi40MSAxOSAxMiAxMy40MSAxNy41OSAxOSAxOSAxNy41OSAxMy40MSAxMiAxOSA2LjQxeiIvPjwvc3ZnPg==';
Editor.trashImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjgwLTEyMHEtMzMgMC01Ni41LTIzLjVUMjAwLTIwMHYtNTIwaC00MHYtODBoMjAwdi00MGgyNDB2NDBoMjAwdjgwaC00MHY1MjBxMCAzMy0yMy41IDU2LjVUNjgwLTEyMEgyODBabTQwMC02MDBIMjgwdjUyMGg0MDB2LTUyMFpNMzYwLTI4MGg4MHYtMzYwaC04MHYzNjBabTE2MCAwaDgwdi0zNjBoLTgwdjM2MFpNMjgwLTcyMHY1MjAtNTIwWiIvPjwvc3ZnPg==';
Editor.hiddenImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDZjMy43OSAwIDcuMTcgMi4xMyA4LjgyIDUuNS0uNTkgMS4yMi0xLjQyIDIuMjctMi40MSAzLjEybDEuNDEgMS40MWMxLjM5LTEuMjMgMi40OS0yLjc3IDMuMTgtNC41M0MyMS4yNyA3LjExIDE3IDQgMTIgNGMtMS4yNyAwLTIuNDkuMi0zLjY0LjU3bDEuNjUgMS42NUMxMC42NiA2LjA5IDExLjMyIDYgMTIgNnptLTEuMDcgMS4xNEwxMyA5LjIxYy41Ny4yNSAxLjAzLjcxIDEuMjggMS4yOGwyLjA3IDIuMDdjLjA4LS4zNC4xNC0uNy4xNC0xLjA3QzE2LjUgOS4wMSAxNC40OCA3IDEyIDdjLS4zNyAwLS43Mi4wNS0xLjA3LjE0ek0yLjAxIDMuODdsMi42OCAyLjY4QzMuMDYgNy44MyAxLjc3IDkuNTMgMSAxMS41IDIuNzMgMTUuODkgNyAxOSAxMiAxOWMxLjUyIDAgMi45OC0uMjkgNC4zMi0uODJsMy40MiAzLjQyIDEuNDEtMS40MUwzLjQyIDIuNDUgMi4wMSAzLjg3em03LjUgNy41bDIuNjEgMi42MWMtLjA0LjAxLS4wOC4wMi0uMTIuMDItMS4zOCAwLTIuNS0xLjEyLTIuNS0yLjUgMC0uMDUuMDEtLjA4LjAxLS4xM3ptLTMuNC0zLjRsMS43NSAxLjc1Yy0uMjMuNTUtLjM2IDEuMTUtLjM2IDEuNzggMCAyLjQ4IDIuMDIgNC41IDQuNSA0LjUuNjMgMCAxLjIzLS4xMyAxLjc3LS4zNmwuOTguOThjLS44OC4yNC0xLjguMzgtMi43NS4zOC0zLjc5IDAtNy4xNy0yLjEzLTguODItNS41LjctMS40MyAxLjcyLTIuNjEgMi45My0zLjUzeiIvPjwvc3ZnPg==';
Editor.visibleImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDZjMy43OSAwIDcuMTcgMi4xMyA4LjgyIDUuNUMxOS4xNyAxNC44NyAxNS43OSAxNyAxMiAxN3MtNy4xNy0yLjEzLTguODItNS41QzQuODMgOC4xMyA4LjIxIDYgMTIgNm0wLTJDNyA0IDIuNzMgNy4xMSAxIDExLjUgMi43MyAxNS44OSA3IDE5IDEyIDE5czkuMjctMy4xMSAxMS03LjVDMjEuMjcgNy4xMSAxNyA0IDEyIDR6bTAgNWMxLjM4IDAgMi41IDEuMTIgMi41IDIuNVMxMy4zOCAxNCAxMiAxNHMtMi41LTEuMTItMi41LTIuNVMxMC42MiA5IDEyIDltMC0yYy0yLjQ4IDAtNC41IDIuMDItNC41IDQuNVM5LjUyIDE2IDEyIDE2czQuNS0yLjAyIDQuNS00LjVTMTQuNDggNyAxMiA3eiIvPjwvc3ZnPg==';
Editor.lockedImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PGcgZmlsbD0ibm9uZSI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6Ii8+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBvcGFjaXR5PSIuODciLz48L2c+PHBhdGggZD0iTTE4IDhoLTFWNmMwLTIuNzYtMi4yNC01LTUtNVM3IDMuMjQgNyA2djJINmMtMS4xIDAtMiAuOS0yIDJ2MTBjMCAxLjEuOSAyIDIgMmgxMmMxLjEgMCAyLS45IDItMlYxMGMwLTEuMS0uOS0yLTItMnpNOSA2YzAtMS42NiAxLjM0LTMgMy0zczMgMS4zNCAzIDN2Mkg5VjZ6bTkgMTRINlYxMGgxMnYxMHptLTYtM2MxLjEgMCAyLS45IDItMnMtLjktMi0yLTItMiAuOS0yIDIgLjkgMiAyIDJ6Ii8+PC9zdmc+';
Editor.unlockedImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE4IDhoLTFWNmMwLTIuNzYtMi4yNC01LTUtNVM3IDMuMjQgNyA2aDJjMC0xLjY2IDEuMzQtMyAzLTNzMyAxLjM0IDMgM3YySDZjLTEuMSAwLTIgLjktMiAydjEwYzAgMS4xLjkgMiAyIDJoMTJjMS4xIDAgMi0uOSAyLTJWMTBjMC0xLjEtLjktMi0yLTJ6bTAgMTJINlYxMGgxMnYxMHptLTYtM2MxLjEgMCAyLS45IDItMnMtLjktMi0yLTItMiAuOS0yIDIgLjkgMiAyIDJ6Ii8+PC9zdmc+';
Editor.printImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNjQwLTY0MHYtMTIwSDMyMHYxMjBoLTgwdi0yMDBoNDgwdjIwMGgtODBabS00ODAgODBoNjQwLTY0MFptNTYwIDEwMHExNyAwIDI4LjUtMTEuNVQ3NjAtNTAwcTAtMTctMTEuNS0yOC41VDcyMC01NDBxLTE3IDAtMjguNSAxMS41VDY4MC01MDBxMCAxNyAxMS41IDI4LjVUNzIwLTQ2MFptLTgwIDI2MHYtMTYwSDMyMHYxNjBoMzIwWm04MCA4MEgyNDB2LTE2MEg4MHYtMjQwcTAtNTEgMzUtODUuNXQ4NS0zNC41aDU2MHE1MSAwIDg1LjUgMzQuNVQ4ODAtNTIwdjI0MEg3MjB2MTYwWm04MC0yNDB2LTE2MHEwLTE3LTExLjUtMjguNVQ3NjAtNTYwSDIwMHEtMTcgMC0yOC41IDExLjVUMTYwLTUyMHYxNjBoODB2LTgwaDQ4MHY4MGg4MFoiLz48L3N2Zz4=';
Editor.refreshImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE3LjY1IDYuMzVDMTYuMiA0LjkgMTQuMjEgNCAxMiA0Yy00LjQyIDAtNy45OSAzLjU4LTcuOTkgOHMzLjU3IDggNy45OSA4YzMuNzMgMCA2Ljg0LTIuNTUgNy43My02aC0yLjA4Yy0uODIgMi4zMy0zLjA0IDQtNS42NSA0LTMuMzEgMC02LTIuNjktNi02czIuNjktNiA2LTZjMS42NiAwIDMuMTQuNjkgNC4yMiAxLjc4TDEzIDExaDdWNGwtMi4zNSAyLjM1eiIvPjwvc3ZnPg==';
Editor.backImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIiBvcGFjaXR5PSIuODciLz48cGF0aCBkPSJNMTcuNTEgMy44N0wxNS43MyAyLjEgNS44NCAxMmw5LjkgOS45IDEuNzctMS43N0w5LjM4IDEybDguMTMtOC4xM3oiLz48L3N2Zz4=';
Editor.closeImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIiBvcGFjaXR5PSIuODciLz48cGF0aCBkPSJNMTIgMkM2LjQ3IDIgMiA2LjQ3IDIgMTJzNC40NyAxMCAxMCAxMCAxMC00LjQ3IDEwLTEwUzE3LjUzIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTMuNTktMTNMMTIgMTAuNTkgOC40MSA3IDcgOC40MSAxMC41OSAxMiA3IDE1LjU5IDguNDEgMTcgMTIgMTMuNDEgMTUuNTkgMTcgMTcgMTUuNTkgMTMuNDEgMTIgMTcgOC40MXoiLz48L3N2Zz4='
Editor.closeBlackImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjZweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjZweCI+PGVsbGlwc2UgY3g9IjEyIiBjeT0iMTIiIHJ4PSI5IiByeT0iOSIgc3Ryb2tlPSJub25lIiBmaWxsPSIjMDAwIi8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE0LjU5IDhMMTIgMTAuNTkgOS40MSA4IDggOS40MSAxMC41OSAxMiA4IDE0LjU5IDkuNDEgMTYgMTIgMTMuNDEgMTQuNTkgMTYgMTYgMTQuNTkgMTMuNDEgMTIgMTYgOS40MSAxNC41OSA4ek0xMiAyQzYuNDcgMiAyIDYuNDcgMiAxMnM0LjQ3IDEwIDEwIDEwIDEwLTQuNDcgMTAtMTBTMTcuNTMgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHoiLz48L3N2Zz4=';
Editor.minusImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0iTTEwIDI1LjV2LTNoMjh2M1oiLz48L3N2Zz4=';
Editor.plusImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgMTNoLTZ2NmgtMnYtNkg1di0yaDZWNWgydjZoNnYyeiIvPjwvc3ZnPg==';
Editor.addBoxImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDQwLTI4MGg4MHYtMTYwaDE2MHYtODBINTIwdi0xNjBoLTgwdjE2MEgyODB2ODBoMTYwdjE2MFpNMjAwLTEyMHEtMzMgMC01Ni41LTIzLjVUMTIwLTIwMHYtNTYwcTAtMzMgMjMuNS01Ni41VDIwMC04NDBoNTYwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2NTYwcTAgMzMtMjMuNSA1Ni41VDc2MC0xMjBIMjAwWm0wLTgwaDU2MHYtNTYwSDIwMHY1NjBabTAtNTYwdjU2MC01NjBaIi8+PC9zdmc+';
Editor.shapesImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNjAwLTM2MFpNMzIwLTI0MnExMCAxIDE5LjUgMS41dDIwLjUuNXExMSAwIDIwLjUtLjVUNDAwLTI0MnY4Mmg0MDB2LTQwMGgtODJxMS0xMCAxLjUtMTkuNXQuNS0yMC41cTAtMTEtLjUtMjAuNVQ3MTgtNjQwaDgycTMzIDAgNTYuNSAyMy41VDg4MC01NjB2NDAwcTAgMzMtMjMuNSA1Ni41VDgwMC04MEg0MDBxLTMzIDAtNTYuNS0yMy41VDMyMC0xNjB2LTgyWm00MC03OHEtMTE3IDAtMTk4LjUtODEuNVQ4MC02MDBxMC0xMTcgODEuNS0xOTguNVQzNjAtODgwcTExNyAwIDE5OC41IDgxLjVUNjQwLTYwMHEwIDExNy04MS41IDE5OC41VDM2MC0zMjBabTAtODBxODMgMCAxNDEuNS01OC41VDU2MC02MDBxMC04My01OC41LTE0MS41VDM2MC04MDBxLTgzIDAtMTQxLjUgNTguNVQxNjAtNjAwcTAgODMgNTguNSAxNDEuNVQzNjAtNDAwWm0wLTIwMFoiLz48L3N2Zz4=';
Editor.formatImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJtMzUyLTUyMiA4Ni04Ny01Ni01Ny00NCA0NC01Ni01NiA0My00NC00NS00NS04NyA4NyAxNTkgMTU4Wm0zMjggMzI5IDg3LTg3LTQ1LTQ1LTQ0IDQzLTU2LTU2IDQzLTQ0LTU3LTU2LTg2IDg2IDE1OCAxNTlabTI0LTU2NyA1NyA1Ny01Ny01N1pNMjkwLTEyMEgxMjB2LTE3MGwxNzUtMTc1TDgwLTY4MGwyMDAtMjAwIDIxNiAyMTYgMTUxLTE1MnExMi0xMiAyNy0xOHQzMS02cTE2IDAgMzEgNnQyNyAxOGw1MyA1NHExMiAxMiAxOCAyN3Q2IDMxcTAgMTYtNiAzMC41VDgxNi02NDdMNjY1LTQ5NWwyMTUgMjE1TDY4MC04MCA0NjUtMjk1IDI5MC0xMjBabS05MC04MGg1NmwzOTItMzkxLTU3LTU3LTM5MSAzOTJ2NTZabTQyMC00MTktMjktMjkgNTcgNTctMjgtMjhaIi8+PC9zdmc+';
Editor.freehandImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHJlY3QgZmlsbD0ibm9uZSIgaGVpZ2h0PSIyNCIgd2lkdGg9IjI0Ii8+PHBhdGggZD0iTTQuNSw4YzEuMDQsMCwyLjM0LTEuNSw0LjI1LTEuNWMxLjUyLDAsMi43NSwxLjIzLDIuNzUsMi43NWMwLDIuMDQtMS45OSwzLjE1LTMuOTEsNC4yMkM1LjQyLDE0LjY3LDQsMTUuNTcsNCwxNyBjMCwxLjEsMC45LDIsMiwydjJjLTIuMjEsMC00LTEuNzktNC00YzAtMi43MSwyLjU2LTQuMTQsNC42Mi01LjI4YzEuNDItMC43OSwyLjg4LTEuNiwyLjg4LTIuNDdjMC0wLjQxLTAuMzQtMC43NS0wLjc1LTAuNzUgQzcuNSw4LjUsNi4yNSwxMCw0LjUsMTBDMy4xMiwxMCwyLDguODgsMiw3LjVDMiw1LjQ1LDQuMTcsMi44Myw1LDJsMS40MSwxLjQxQzUuNDEsNC40Miw0LDYuNDMsNCw3LjVDNCw3Ljc4LDQuMjIsOCw0LjUsOHogTTgsMjEgbDMuNzUsMGw4LjA2LTguMDZsLTMuNzUtMy43NUw4LDE3LjI1TDgsMjF6IE0xMCwxOC4wOGw2LjA2LTYuMDZsMC45MiwwLjkyTDEwLjkyLDE5TDEwLDE5TDEwLDE4LjA4eiBNMjAuMzcsNi4yOSBjLTAuMzktMC4zOS0xLjAyLTAuMzktMS40MSwwbC0xLjgzLDEuODNsMy43NSwzLjc1bDEuODMtMS44M2MwLjM5LTAuMzksMC4zOS0xLjAyLDAtMS40MUwyMC4zNyw2LjI5eiIvPjwvc3ZnPg==';
Editor.undoImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjgwLTIwMHYtODBoMjg0cTYzIDAgMTA5LjUtNDBUNzIwLTQyMHEwLTYwLTQ2LjUtMTAwVDU2NC01NjBIMzEybDEwNCAxMDQtNTYgNTYtMjAwLTIwMCAyMDAtMjAwIDU2IDU2LTEwNCAxMDRoMjUycTk3IDAgMTY2LjUgNjNUODAwLTQyMHEwIDk0LTY5LjUgMTU3VDU2NC0yMDBIMjgwWiIvPjwvc3ZnPg==';
Editor.redoImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzk2LTIwMHEtOTcgMC0xNjYuNS02M1QxNjAtNDIwcTAtOTQgNjkuNS0xNTdUMzk2LTY0MGgyNTJMNTQ0LTc0NGw1Ni01NiAyMDAgMjAwLTIwMCAyMDAtNTYtNTYgMTA0LTEwNEgzOTZxLTYzIDAtMTA5LjUgNDBUMjQwLTQyMHEwIDYwIDQ2LjUgMTAwVDM5Ni0yODBoMjg0djgwSDM5NloiLz48L3N2Zz4=';
Editor.outlineImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTE1IDIxLTYtMi4xLTQuNjUgMS44cS0uNS4yLS45MjUtLjExM1EzIDIwLjI3NSAzIDE5Ljc1di0xNHEwLS4zMjUuMTg4LS41NzUuMTg3LS4yNS41MTItLjM3NUw5IDNsNiAyLjEgNC42NS0xLjhxLjUtLjIuOTI1LjExMi40MjUuMzEzLjQyNS44Mzh2MTRxMCAuMzI1LS4xODguNTc1LS4xODcuMjUtLjUxMi4zNzVabS0xLTIuNDVWNi44NWwtNC0xLjR2MTEuN1ptMiAwIDMtMVY1LjdsLTMgMS4xNVpNNSAxOC4zbDMtMS4xNVY1LjQ1bC0zIDFaTTE2IDYuODV2MTEuN1ptLTgtMS40djExLjdaIi8+PC9zdmc+';
Editor.saveImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDEydjdINXYtN0gzdjdjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMnYtN2gtMnptLTYgLjY3bDIuNTktMi41OEwxNyAxMS41bC01IDUtNS01IDEuNDEtMS40MUwxMSAxMi42N1YzaDJ2OS42N3oiLz48L3N2Zz4=';
Editor.compareImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0ibTE1Ljg1IDQwLTIuMS0yLjEgNi4wNS02LjA1SDR2LTNoMTUuOGwtNi4wNS02LjA1IDIuMS0yLjEgOS42NSA5LjY1Wm0xNi4zLTEyLjctOS42NS05LjY1TDMyLjE1IDhsMi4xIDIuMS02LjA1IDYuMDVINDR2M0gyOC4ybDYuMDUgNi4wNVoiLz48L3N2Zz4=';
Editor.expandMoreImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTEyIDE1LjM3NS02LTYgMS40LTEuNCA0LjYgNC42IDQuNi00LjYgMS40IDEuNFoiLz48L3N2Zz4=';
Editor.expandLessImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTcuNCAxNS4zNzUtMS40LTEuNCA2LTYgNiA2LTEuNCAxLjQtNC42LTQuNloiLz48L3N2Zz4=';
Editor.gearImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTkuMjUgMjItLjQtMy4ycS0uMzI1LS4xMjUtLjYxMi0uMy0uMjg4LS4xNzUtLjU2My0uMzc1TDQuNyAxOS4zNzVsLTIuNzUtNC43NSAyLjU3NS0xLjk1UTQuNSAxMi41IDQuNSAxMi4zMzd2LS42NzVxMC0uMTYyLjAyNS0uMzM3TDEuOTUgOS4zNzVsMi43NS00Ljc1IDIuOTc1IDEuMjVxLjI3NS0uMi41NzUtLjM3NS4zLS4xNzUuNi0uM2wuNC0zLjJoNS41bC40IDMuMnEuMzI1LjEyNS42MTMuMy4yODcuMTc1LjU2Mi4zNzVsMi45NzUtMS4yNSAyLjc1IDQuNzUtMi41NzUgMS45NXEuMDI1LjE3NS4wMjUuMzM3di42NzVxMCAuMTYzLS4wNS4zMzhsMi41NzUgMS45NS0yLjc1IDQuNzUtMi45NS0xLjI1cS0uMjc1LjItLjU3NS4zNzUtLjMuMTc1LS42LjNsLS40IDMuMlptMi44LTYuNXExLjQ1IDAgMi40NzUtMS4wMjVRMTUuNTUgMTMuNDUgMTUuNTUgMTJxMC0xLjQ1LTEuMDI1LTIuNDc1UTEzLjUgOC41IDEyLjA1IDguNXEtMS40NzUgMC0yLjQ4OCAxLjAyNVE4LjU1IDEwLjU1IDguNTUgMTJxMCAxLjQ1IDEuMDEyIDIuNDc1UTEwLjU3NSAxNS41IDEyLjA1IDE1LjVabTAtMnEtLjYyNSAwLTEuMDYyLS40MzgtLjQzOC0uNDM3LS40MzgtMS4wNjJ0LjQzOC0xLjA2MnEuNDM3LS40MzggMS4wNjItLjQzOHQxLjA2My40MzhxLjQzNy40MzcuNDM3IDEuMDYydC0uNDM3IDEuMDYycS0uNDM4LjQzOC0xLjA2My40MzhaTTEyIDEyWm0tMSA4aDEuOTc1bC4zNS0yLjY1cS43NzUtLjIgMS40MzgtLjU4OC42NjItLjM4NyAxLjIxMi0uOTM3bDIuNDc1IDEuMDI1Ljk3NS0xLjctMi4xNS0xLjYyNXEuMTI1LS4zNS4xNzUtLjczOC4wNS0uMzg3LjA1LS43ODd0LS4wNS0uNzg4cS0uMDUtLjM4Ny0uMTc1LS43MzdsMi4xNS0xLjYyNS0uOTc1LTEuNy0yLjQ3NSAxLjA1cS0uNTUtLjU3NS0xLjIxMi0uOTYzLS42NjMtLjM4Ny0xLjQzOC0uNTg3TDEzIDRoLTEuOTc1bC0uMzUgMi42NXEtLjc3NS4yLTEuNDM3LjU4Ny0uNjYzLjM4OC0xLjIxMy45MzhMNS41NSA3LjE1bC0uOTc1IDEuNyAyLjE1IDEuNnEtLjEyNS4zNzUtLjE3NS43NS0uMDUuMzc1LS4wNS44IDAgLjQuMDUuNzc1dC4xNzUuNzVsLTIuMTUgMS42MjUuOTc1IDEuNyAyLjQ3NS0xLjA1cS41NS41NzUgMS4yMTMuOTYyLjY2Mi4zODggMS40MzcuNTg4WiIvPjwvc3ZnPg==';
Editor.extensionImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTguOCAyMUg1cS0uODI1IDAtMS40MTMtLjU4N1EzIDE5LjgyNSAzIDE5di0zLjhxMS4yIDAgMi4xLS43NjIuOS0uNzYzLjktMS45MzggMC0xLjE3NS0uOS0xLjkzOFE0LjIgOS44IDMgOS44VjZxMC0uODI1LjU4Ny0xLjQxMlE0LjE3NSA0IDUgNGg0cTAtMS4wNS43MjUtMS43NzVRMTAuNDUgMS41IDExLjUgMS41cTEuMDUgMCAxLjc3NS43MjVRMTQgMi45NSAxNCA0aDRxLjgyNSAwIDEuNDEzLjU4OFEyMCA1LjE3NSAyMCA2djRxMS4wNSAwIDEuNzc1LjcyNS43MjUuNzI1LjcyNSAxLjc3NSAwIDEuMDUtLjcyNSAxLjc3NVEyMS4wNSAxNSAyMCAxNXY0cTAgLjgyNS0uNTg3IDEuNDEzUTE4LjgyNSAyMSAxOCAyMWgtMy44cTAtMS4yNS0uNzg3LTIuMTI1UTEyLjYyNSAxOCAxMS41IDE4dC0xLjkxMi44NzVROC44IDE5Ljc1IDguOCAyMVpNNSAxOWgyLjEyNXEuNi0xLjY1IDEuOTI1LTIuMzI1UTEwLjM3NSAxNiAxMS41IDE2cTEuMTI1IDAgMi40NS42NzUgMS4zMjUuNjc1IDEuOTI1IDIuMzI1SDE4di02aDJxLjIgMCAuMzUtLjE1LjE1LS4xNS4xNS0uMzUgMC0uMi0uMTUtLjM1UTIwLjIgMTIgMjAgMTJoLTJWNmgtNlY0cTAtLjItLjE1LS4zNS0uMTUtLjE1LS4zNS0uMTUtLjIgMC0uMzUuMTVRMTEgMy44IDExIDR2Mkg1djIuMnExLjM1LjUgMi4xNzUgMS42NzVROCAxMS4wNSA4IDEyLjVxMCAxLjQyNS0uODI1IDIuNlQ1IDE2LjhabTcuNzUtNy43NVoiLz48L3N2Zz4=';
Editor.colorDropperImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0iTTYgNDJ2LTguNGwxOC44NS0xOC44NS0zLjYtMy42TDIzLjMgOS4xbDQuNiA0LjZMMzUgNi42cS41NS0uNTUgMS4xNzUtLjU1dDEuMTc1LjU1bDQuMDUgNC4wNXEuNTUuNTUuNTUgMS4xNzVUNDEuNCAxM2wtNy4xIDcuMSA0LjYgNC42LTIuMDUgMi4wNS0zLjYtMy42TDE0LjQgNDJabTMtM2g0LjM1TDMxLjEgMjEuMjVsLTQuMzUtNC4zNUw5IDM0LjY1Wm0yMy4xNS0yMSA2LjItNi4yLTIuMTUtMi4xNS02LjIgNi4yWm0wIDBMMzAgMTUuODUgMzIuMTUgMThaIi8+PC9zdmc+';
Editor.magnifyImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik03ODQtMTIwIDUzMi0zNzJxLTMwIDI0LTY5IDM4dC04MyAxNHEtMTA5IDAtMTg0LjUtNzUuNVQxMjAtNTgwcTAtMTA5IDc1LjUtMTg0LjVUMzgwLTg0MHExMDkgMCAxODQuNSA3NS41VDY0MC01ODBxMCA0NC0xNCA4M3QtMzggNjlsMjUyIDI1Mi01NiA1NlpNMzgwLTQwMHE3NSAwIDEyNy41LTUyLjVUNTYwLTU4MHEwLTc1LTUyLjUtMTI3LjVUMzgwLTc2MHEtNzUgMC0xMjcuNSA1Mi41VDIwMC01ODBxMCA3NSA1Mi41IDEyNy41VDM4MC00MDBaIi8+PC9zdmc+';
Editor.sendImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik0xMjAtMTYwdi02NDBsNzYwIDMyMC03NjAgMzIwWm04MC0xMjAgNDc0LTIwMC00NzQtMjAwdjE0MGwyNDAgNjAtMjQwIDYwdjE0MFptMCAwdi00MDAgNDAwWiIvPjwvc3ZnPg==';
Editor.sparklesImage = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjkyLDI2Mi45MSwyMTYuNCwxNDkuNzdhOSw5LDAsMCwwLTE2LjgsMEwxNTYuMDgsMjYyLjkxYTksOSwwLDAsMS01LjE3LDUuMTdMMzcuNzcsMzExLjZhOSw5LDAsMCwwLDAsMTYuOGwxMTMuMTQsNDMuNTJhOSw5LDAsMCwxLDUuMTcsNS4xN0wxOTkuNiw0OTAuMjNhOSw5LDAsMCwwLDE2LjgsMGw0My41Mi0xMTMuMTRhOSw5LDAsMCwxLDUuMTctNS4xN0wzNzguMjMsMzI4LjRhOSw5LDAsMCwwLDAtMTYuOEwyNjUuMDksMjY4LjA4QTksOSwwLDAsMSwyNTkuOTIsMjYyLjkxWiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iNDAiIGRhdGEtZGFya3JlYWRlci1pbmxpbmUtc3Ryb2tlPSIiIHN0eWxlPSItLWRhcmtyZWFkZXItaW5saW5lLXN0cm9rZTogIzE4MWExYjsiLz4KPHBvbHlnb24gcG9pbnRzPSIxMDggNjggODggMTYgNjggNjggMTYgODggNjggMTA4IDg4IDE2MCAxMDggMTA4IDE2MCA4OCAxMDggNjgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjMwIi8+Cjxwb2x5Z29uIHBvaW50cz0iNDI2LjY3IDExNy4zMyA0MDAgNDggMzczLjMzIDExNy4zMyAzMDQgMTQ0IDM3My4zMyAxNzAuNjcgNDAwIDI0MCA0MjYuNjcgMTcwLjY3IDQ5NiAxNDQgNDI2LjY3IDExNy4zMyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMzAiLz4KPC9zdmc+';
Editor.thinSparklesImage = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIgogICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0yNTkuOTIsMjYyLjkxLDIxNi40LDE0OS43N2E5LDksMCwwLDAtMTYuOCwwTDE1Ni4wOCwyNjIuOTFhOSw5LDAsMCwxLTUuMTcsNS4xN0wzNy43NywzMTEuNmE5LDksMCwwLDAsMCwxNi44bDExMy4xNCw0My41MmE5LDksMCwwLDEsNS4xNyw1LjE3TDE5OS42LDQ5MC4yM2E5LDksMCwwLDAsMTYuOCwwbDQzLjUyLTExMy4xNGE5LDksMCwwLDEsNS4xNy01LjE3TDM3OC4yMywzMjguNGE5LDksMCwwLDAsMC0xNi44TDI2NS4wOSwyNjguMDhBOSw5LDAsMCwxLDI1OS45MiwyNjIuOTFaIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyNCIgZGF0YS1kYXJrcmVhZGVyLWlubGluZS1zdHJva2U9IiIgc3R5bGU9Ii0tZGFya3JlYWRlci1pbmxpbmUtc3Ryb2tlOiAjMTgxYTFiOyIvPgogICAgPHBvbHlnb24gcG9pbnRzPSIxMDggNjggODggMTYgNjggNjggMTYgODggNjggMTA4IDg4IDE2MCAxMDggMTA4IDE2MCA4OCAxMDggNjgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjI0Ii8+CiAgICA8cG9seWdvbiBwb2ludHM9IjQyNi42NyAxMTcuMzMgNDAwIDQ4IDM3My4zMyAxMTcuMzMgMzA0IDE0NCAzNzMuMzMgMTcwLjY3IDQwMCAyNDAgNDI2LjY3IDE3MC42NyA0OTYgMTQ0IDQyNi42NyAxMTcuMzMiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjI0Ii8+Cjwvc3ZnPg==';
Editor.arrowRightImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDAwLTI4MHYtNDAwbDIwMCAyMDAtMjAwIDIwMFoiLz48L3N2Zz4=';
Editor.arrowDownImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDgwLTM2MCAyODAtNTYwaDQwMEw0ODAtMzYwWiIvPjwvc3ZnPg==';
Editor.arrowUpImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJtMjgwLTQwMCAyMDAtMjAwIDIwMCAyMDBIMjgwWiIvPjwvc3ZnPg==';
Editor.refreshImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDgwLTE2MHEtMTM0IDAtMjI3LTkzdC05My0yMjdxMC0xMzQgOTMtMjI3dDIyNy05M3E2OSAwIDEzMiAyOC41VDcyMC02OTB2LTExMGg4MHYyODBINTIwdi04MGgxNjhxLTMyLTU2LTg3LjUtODhUNDgwLTcyMHEtMTAwIDAtMTcwIDcwdC03MCAxNzBxMCAxMDAgNzAgMTcwdDE3MCA3MHE3NyAwIDEzOS00NHQ4Ny0xMTZoODRxLTI4IDEwNi0xMTQgMTczdC0xOTYgNjdaIi8+PC9zdmc+';
Editor.checkImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzgyLTI0MCAxNTQtNDY4bDU3LTU3IDE3MSAxNzEgMzY3LTM2NyA1NyA1Ny00MjQgNDI0WiIvPjwvc3ZnPg==';
Editor.dockRightImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTEyMHEtMzMgMC01Ni41LTIzLjVUMTIwLTIwMHYtNTYwcTAtMzMgMjMuNS01Ni41VDIwMC04NDBoNTYwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2NTYwcTAgMzMtMjMuNSA1Ni41VDc2MC0xMjBIMjAwWm0xMjAtODB2LTU2MEgyMDB2NTYwaDEyMFptODAgMGgzNjB2LTU2MEg0MDB2NTYwWm0tODAgMEgyMDBoMTIwWiIvPjwvc3ZnPg==';
Editor.toFrontImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzYwLTI4MHEtMzMgMC01Ni41LTIzLjVUMjgwLTM2MHYtNDAwcTAtMzMgMjMuNS01Ni41VDM2MC04NDBoNDAwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2NDAwcTAgMzMtMjMuNSA1Ni41VDc2MC0yODBIMzYwWm0wLTgwaDQwMHYtNDAwSDM2MHY0MDBaTTIwMC0yMDB2ODBxLTMzIDAtNTYuNS0yMy41VDEyMC0yMDBoODBabS04MC04MHYtODBoODB2ODBoLTgwWm0wLTE2MHYtODBoODB2ODBoLTgwWm0wLTE2MHYtODBoODB2ODBoLTgwWm0xNjAgNDgwdi04MGg4MHY4MGgtODBabTE2MCAwdi04MGg4MHY4MGgtODBabTE2MCAwdi04MGg4MHY4MGgtODBaIi8+PC9zdmc+';
Editor.toBackImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTEyMHEtMzMgMC01Ni41LTIzLjVUMTIwLTIwMHYtNDgwaDgwdjQ4MGg0ODB2ODBIMjAwWm0xNjAtMjQwdjgwcS0zMyAwLTU2LjUtMjMuNVQyODAtMzYwaDgwWm0tODAtODB2LTgwaDgwdjgwaC04MFptMC0xNjB2LTgwaDgwdjgwaC04MFptODAtMTYwaC04MHEwLTMzIDIzLjUtNTYuNVQzNjAtODQwdjgwWm04MCA0ODB2LTgwaDgwdjgwaC04MFptMC00ODB2LTgwaDgwdjgwaC04MFptMTYwIDB2LTgwaDgwdjgwaC04MFptMCA0ODB2LTgwaDgwdjgwaC04MFptMTYwLTQ4MHYtODBxMzMgMCA1Ni41IDIzLjVUODQwLTc2MGgtODBabTAgNDAwaDgwcTAgMzMtMjMuNSA1Ni41VDc2MC0yODB2LTgwWm0wLTgwdi04MGg4MHY4MGgtODBabTAtMTYwdi04MGg4MHY4MGgtODBaIi8+PC9zdmc+';
Editor.fillColorImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJtMjQ3LTkwNCA1Ny01NiAzNDMgMzQzcTIzIDIzIDIzIDU3dC0yMyA1N0w0NTctMzEzcS0yMyAyMy01NyAyM3QtNTctMjNMMTUzLTUwM3EtMjMtMjMtMjMtNTd0MjMtNTdsMTkwLTE5MS05Ni05NlptMTUzIDE1M0wyMDktNTYwaDM4Mkw0MDAtNzUxWm0zNjAgNDcxcS0zMyAwLTU2LjUtMjMuNVQ2ODAtMzYwcTAtMjEgMTIuNS00NXQyNy41LTQ1cTktMTIgMTktMjV0MjEtMjVxMTEgMTIgMjEgMjV0MTkgMjVxMTUgMjEgMjcuNSA0NXQxMi41IDQ1cTAgMzMtMjMuNSA1Ni41VDc2MC0yODBaTTgwIDB2LTE2MGg4MDBWMEg4MFoiLz48L3N2Zz4=';
Editor.strokeColorImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAgMHYtMTYwaDgwMFYwSDgwWm0xNjAtMzIwaDU2bDMxMi0zMTEtMjktMjktMjgtMjgtMzExIDMxMnY1NlptLTgwIDgwdi0xNzBsNDQ4LTQ0N3ExMS0xMSAyNS41LTE3dDMwLjUtNnExNiAwIDMxIDZ0MjcgMThsNTUgNTZxMTIgMTEgMTcuNSAyNnQ1LjUgMzFxMCAxNS01LjUgMjkuNVQ3NzctNjg3TDMzMC0yNDBIMTYwWm01NjAtNTA0LTU2LTU2IDU2IDU2Wk02MDgtNjMxbC0yOS0yOS0yOC0yOCA1NyA1N1oiLz48L3N2Zz4=';
Editor.fontColorImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAgMHYtMTYwaDgwMFYwSDgwWm0xNDAtMjgwIDIxMC01NjBoMTAwbDIxMCA1NjBoLTk2bC01MC0xNDRIMzY4bC01MiAxNDRoLTk2Wm0xNzYtMjI0aDE2OGwtODItMjMyaC00bC04MiAyMzJaIi8+PC9zdmc+';
Editor.backgroundColorImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAgMHYtMTYwaDgwMFYwSDgwWm01MDQtNDgwTDQ4MC01ODQgMzIwLTQyNGwxMDMgMTA0IDE2MS0xNjBabS00Ny0xNjAgMTAzIDEwMyAxNjAtMTU5LTEwNC0xMDQtMTU5IDE2MFptLTg0LTI5IDIxNiAyMTYtMTg5IDE5MHEtMjQgMjQtNTYuNSAyNFQzNjctMjYzbC0yNyAyM0gxNDBsMTI2LTEyNXEtMjQtMjQtMjUtNTcuNXQyMy01Ny41bDE4OS0xODlabTAgMCAxODctMTg3cTI0LTI0IDU2LjUtMjR0NTYuNSAyNGwxMDQgMTAzcTI0IDI0IDI0IDU2LjVUODU3LTY0MEw2NjktNDUzIDQ1My02NjlaIi8+PC9zdmc+';
Editor.shadowImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTYwLTgwcS0zMyAwLTU2LjUtMjMuNVQ4MC0xNjB2LTQ4MHEwLTMzIDIzLjUtNTYuNVQxNjAtNzIwaDgwdi04MHEwLTMzIDIzLjUtNTYuNVQzMjAtODgwaDQ4MHEzMyAwIDU2LjUgMjMuNVQ4ODAtODAwdjQ4MHEwIDMzLTIzLjUgNTYuNVQ4MDAtMjQwaC04MHY4MHEwIDMzLTIzLjUgNTYuNVQ2NDAtODBIMTYwWm0xNjAtMjQwaDQ4MHYtNDgwSDMyMHY0ODBaIi8+PC9zdmc+';
Editor.boldImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjcyLTIwMHYtNTYwaDIyMXE2NSAwIDEyMCA0MHQ1NSAxMTFxMCA1MS0yMyA3OC41VDYwMi00OTFxMjUgMTEgNTUuNSA0MXQzMC41IDkwcTAgODktNjUgMTI0LjVUNTAxLTIwMEgyNzJabTEyMS0xMTJoMTA0cTQ4IDAgNTguNS0yNC41VDU2Ni0zNzJxMC0xMS0xMC41LTM1LjVUNDk0LTQzMkgzOTN2MTIwWm0wLTIyOGg5M3EzMyAwIDQ4LTE3dDE1LTM4cTAtMjQtMTctMzl0LTQ0LTE1aC05NXYxMDlaIi8+PC9zdmc+';
Editor.italicImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTIwMHYtMTAwaDE2MGwxMjAtMzYwSDMyMHYtMTAwaDQwMHYxMDBINTgwTDQ2MC0zMDBoMTQwdjEwMEgyMDBaIi8+PC9zdmc+';
Editor.underlineImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTEyMHYtODBoNTYwdjgwSDIwMFptMjgwLTE2MHEtMTAxIDAtMTU3LTYzdC01Ni0xNjd2LTMzMGgxMDN2MzM2cTAgNTYgMjggOTF0ODIgMzVxNTQgMCA4Mi0zNXQyOC05MXYtMzM2aDEwM3YzMzBxMCAxMDQtNTYgMTY3dC0xNTcgNjNaIi8+PC9zdmc+';
Editor.strikethroughImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDg2LTE2MHEtNzYgMC0xMzUtNDV0LTg1LTEyM2w4OC0zOHExNCA0OCA0OC41IDc5dDg1LjUgMzFxNDIgMCA3Ni0yMHQzNC02NHEwLTE4LTctMzN0LTE5LTI3aDExMnE1IDE0IDcuNSAyOC41VDY5NC0zNDBxMCA4Ni02MS41IDEzM1Q0ODYtMTYwWk04MC00ODB2LTgwaDgwMHY4MEg4MFptNDAyLTMyNnE2NiAwIDExNS41IDMyLjVUNjc0LTY3NGwtODggMzlxLTktMjktMzMuNS01MlQ0ODQtNzEwcS00MSAwLTY4IDE4LjVUMzg2LTY0MGgtOTZxMi02OSA1NC41LTExNy41VDQ4Mi04MDZaIi8+PC9zdmc+';
Editor.verticalTextImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzYwLTE2MGgtODB2LTUyOGwtNDIgNDItNTYtNTYgMTM4LTEzOCAxNDAgMTM4LTU4IDU2LTQyLTQydjUyOFpNNTYwLTI3NiAxMjAtNDQwdi04MGw0NDAtMTY0djc2bC0xMTIgMzh2MTc4bDExMiA0MHY3NlpNMzg0LTQxNHYtMTMybC0xODIgNjR2NGwxODIgNjRaIi8+PC9zdmc+';
Editor.alignLeftImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFptMC0xNjB2LTgwaDQ4MHY4MEgxMjBabTAtMTYwdi04MGg3MjB2ODBIMTIwWm0wLTE2MHYtODBoNDgwdjgwSDEyMFptMC0xNjB2LTgwaDcyMHY4MEgxMjBaIi8+PC9zdmc+';
Editor.alignCenterImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFptMTYwLTE2MHYtODBoNDAwdjgwSDI4MFpNMTIwLTQ0MHYtODBoNzIwdjgwSDEyMFptMTYwLTE2MHYtODBoNDAwdjgwSDI4MFpNMTIwLTc2MHYtODBoNzIwdjgwSDEyMFoiLz48L3N2Zz4=';
Editor.alignRightImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTc2MHYtODBoNzIwdjgwSDEyMFptMjQwIDE2MHYtODBoNDgwdjgwSDM2MFpNMTIwLTQ0MHYtODBoNzIwdjgwSDEyMFptMjQwIDE2MHYtODBoNDgwdjgwSDM2MFpNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFoiLz48L3N2Zz4=';
Editor.alignJustifyImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFptMC0xNjB2LTgwaDcyMHY4MEgxMjBabTAtMTYwdi04MGg3MjB2ODBIMTIwWm0wLTE2MHYtODBoNzIwdjgwSDEyMFptMC0xNjB2LTgwaDcyMHY4MEgxMjBaIi8+PC9zdmc+';
Editor.alignTopImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTYwLTc2MHYtODBoNjQwdjgwSDE2MFptMjgwIDY0MHYtNDA4TDMzNi00MjRsLTU2LTU2IDIwMC0yMDAgMjAwIDIwMC01NiA1Ni0xMDQtMTA0djQwOGgtODBaIi8+PC9zdmc+';
Editor.alignMiddleImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDQwLTgwdi0xNjhsLTY0IDY0LTU2LTU2IDE2MC0xNjAgMTYwIDE2MC01NiA1Ni02NC02NHYxNjhoLTgwWk0xNjAtNDQwdi04MGg2NDB2ODBIMTYwWm0zMjAtMTIwTDMyMC03MjBsNTYtNTYgNjQgNjR2LTE2OGg4MHYxNjhsNjQtNjQgNTYgNTYtMTYwIDE2MFoiLz48L3N2Zz4=';
Editor.alignBottomImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTYwLTEyMHYtODBoNjQwdjgwSDE2MFptMzIwLTE2MEwyODAtNDgwbDU2LTU2IDEwNCAxMDR2LTQwOGg4MHY0MDhsMTA0LTEwNCA1NiA1Ni0yMDAgMjAwWiIvPjwvc3ZnPg==';
Editor.alignHorizontalLeftImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAtODB2LTgwMGg4MHY4MDBIODBabTE2MC0yMDB2LTEyMGg0MDB2MTIwSDI0MFptMC0yODB2LTEyMGg2NDB2MTIwSDI0MFoiLz48L3N2Zz4=';
Editor.alignHorizontalCenterImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDQwLTgwdi0yMDBIMjQwdi0xMjBoMjAwdi0xNjBIMTIwdi0xMjBoMzIwdi0yMDBoODB2MjAwaDMyMHYxMjBINTIwdjE2MGgyMDB2MTIwSDUyMHYyMDBoLTgwWiIvPjwvc3ZnPg==';
Editor.alignHorizontalRightImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAwLTgwdi04MDBoODB2ODAwaC04MFpNMzIwLTI4MHYtMTIwaDQwMHYxMjBIMzIwWk04MC01NjB2LTEyMGg2NDB2MTIwSDgwWiIvPjwvc3ZnPg==';
Editor.alignVerticalTopImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjgwLTgwdi02NDBoMTIwdjY0MEgyODBabTI4MC0yNDB2LTQwMGgxMjB2NDAwSDU2MFpNODAtODAwdi04MGg4MDB2ODBIODBaIi8+PC9zdmc+';
Editor.alignVerticalMiddleImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjgwLTEyMHYtMzIwSDgwdi04MGgyMDB2LTMyMGgxMjB2MzIwaDE2MHYtMjAwaDEyMHYyMDBoMjAwdjgwSDY4MHYyMDBINTYwdi0yMDBINDAwdjMyMEgyODBaIi8+PC9zdmc+';
Editor.alignVerticalBottomImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAtODB2LTgwaDgwMHY4MEg4MFptMjAwLTE2MHYtNjQwaDEyMHY2NDBIMjgwWm0yODAgMHYtNDAwaDEyMHY0MDBINTYwWiIvPjwvc3ZnPg==';
Editor.subscriptImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzYwLTE2MHYtODBxMC0xNyAxMS41LTI4LjVUODAwLTI4MGg4MHYtNDBINzYwdi00MGgxMjBxMTcgMCAyOC41IDExLjVUOTIwLTMyMHY0MHEwIDE3LTExLjUgMjguNVQ4ODAtMjQwaC04MHY0MGgxMjB2NDBINzYwWm0tNTI1LTgwIDE4NS0yOTEtMTcyLTI2OWgxMDZsMTI0IDIwMGg0bDEyMy0yMDBoMTA3TDUzOS01MzFsMTg2IDI5MUg2MThMNDgyLTQ1N2gtNEwzNDItMjQwSDIzNVoiLz48L3N2Zz4=';
Editor.superscriptImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzYwLTYwMHYtODBxMC0xNyAxMS41LTI4LjVUODAwLTcyMGg4MHYtNDBINzYwdi00MGgxMjBxMTcgMCAyOC41IDExLjVUOTIwLTc2MHY0MHEwIDE3LTExLjUgMjguNVQ4ODAtNjgwaC04MHY0MGgxMjB2NDBINzYwWk0yMzUtMTYwbDE4NS0yOTEtMTcyLTI2OWgxMDZsMTI0IDIwMGg0bDEyMy0yMDBoMTA3TDUzOS00NTFsMTg2IDI5MUg2MThMNDgyLTM3N2gtNEwzNDItMTYwSDIzNVoiLz48L3N2Zz4=';
Editor.orderedListImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTgwdi02MGgxMDB2LTMwaC02MHYtNjBoNjB2LTMwSDEyMHYtNjBoMTIwcTE3IDAgMjguNSAxMS41VDI4MC0yODB2NDBxMCAxNy0xMS41IDI4LjVUMjQwLTIwMHExNyAwIDI4LjUgMTEuNVQyODAtMTYwdjQwcTAgMTctMTEuNSAyOC41VDI0MC04MEgxMjBabTAtMjgwdi0xMTBxMC0xNyAxMS41LTI4LjVUMTYwLTUxMGg2MHYtMzBIMTIwdi02MGgxMjBxMTcgMCAyOC41IDExLjVUMjgwLTU2MHY3MHEwIDE3LTExLjUgMjguNVQyNDAtNDUwaC02MHYzMGgxMDB2NjBIMTIwWm02MC0yODB2LTE4MGgtNjB2LTYwaDEyMHYyNDBoLTYwWm0xODAgNDQwdi04MGg0ODB2ODBIMzYwWm0wLTI0MHYtODBoNDgwdjgwSDM2MFptMC0yNDB2LTgwaDQ4MHY4MEgzNjBaIi8+PC9zdmc+';
Editor.unorderedListImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzYwLTIwMHYtODBoNDgwdjgwSDM2MFptMC0yNDB2LTgwaDQ4MHY4MEgzNjBabTAtMjQwdi04MGg0ODB2ODBIMzYwWk0yMDAtMTYwcS0zMyAwLTU2LjUtMjMuNVQxMjAtMjQwcTAtMzMgMjMuNS01Ni41VDIwMC0zMjBxMzMgMCA1Ni41IDIzLjVUMjgwLTI0MHEwIDMzLTIzLjUgNTYuNVQyMDAtMTYwWm0wLTI0MHEtMzMgMC01Ni41LTIzLjVUMTIwLTQ4MHEwLTMzIDIzLjUtNTYuNVQyMDAtNTYwcTMzIDAgNTYuNSAyMy41VDI4MC00ODBxMCAzMy0yMy41IDU2LjVUMjAwLTQwMFptMC0yNDBxLTMzIDAtNTYuNS0yMy41VDEyMC03MjBxMC0zMyAyMy41LTU2LjVUMjAwLTgwMHEzMyAwIDU2LjUgMjMuNVQyODAtNzIwcTAgMzMtMjMuNSA1Ni41VDIwMC02NDBaIi8+PC9zdmc+';
Editor.indentImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFptMzIwLTE2MHYtODBoNDAwdjgwSDQ0MFptMC0xNjB2LTgwaDQwMHY4MEg0NDBabTAtMTYwdi04MGg0MDB2ODBINDQwWk0xMjAtNzYwdi04MGg3MjB2ODBIMTIwWm0wIDQ0MHYtMzIwbDE2MCAxNjAtMTYwIDE2MFoiLz48L3N2Zz4=';
Editor.outdentImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTIwLTEyMHYtODBoNzIwdjgwSDEyMFptMzIwLTE2MHYtODBoNDAwdjgwSDQ0MFptMC0xNjB2LTgwaDQwMHY4MEg0NDBabTAtMTYwdi04MGg0MDB2ODBINDQwWk0xMjAtNzYwdi04MGg3MjB2ODBIMTIwWm0xNjAgNDQwTDEyMC00ODBsMTYwLTE2MHYzMjBaIi8+PC9zdmc+';
Editor.removeFormatImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJtNTI4LTU0Ni05My05My0xMjEtMTIxaDQ4NnYxMjBINTY4bC00MCA5NFpNNzkyLTU2IDQ2MC0zODhsLTgwIDE4OEgyNDlsMTE5LTI4MEw1Ni03OTJsNTYtNTYgNzM2IDczNi01NiA1NloiLz48L3N2Zz4=';
Editor.textFormatImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTIwMHYtODBoNTYwdjgwSDIwMFptNzYtMTYwIDE2NC00NDBoODBsMTY0IDQ0MGgtNzZsLTM4LTExMkgzOTJsLTQwIDExMmgtNzZabTEzOC0xNzZoMTMybC02NC0xODJoLTRsLTY0IDE4MloiLz48L3N2Zz4=';
Editor.codeImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzIwLTI0MCA4MC00ODBsMjQwLTI0MCA1NyA1Ny0xODQgMTg0IDE4MyAxODMtNTYgNTZabTMyMCAwLTU3LTU3IDE4NC0xODQtMTgzLTE4MyA1Ni01NiAyNDAgMjQwLTI0MCAyNDBaIi8+PC9zdmc+';
Editor.linkImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDQwLTI4MEgyODBxLTgzIDAtMTQxLjUtNTguNVQ4MC00ODBxMC04MyA1OC41LTE0MS41VDI4MC02ODBoMTYwdjgwSDI4MHEtNTAgMC04NSAzNXQtMzUgODVxMCA1MCAzNSA4NXQ4NSAzNWgxNjB2ODBaTTMyMC00NDB2LTgwaDMyMHY4MEgzMjBabTIwMCAxNjB2LTgwaDE2MHE1MCAwIDg1LTM1dDM1LTg1cTAtNTAtMzUtODV0LTg1LTM1SDUyMHYtODBoMTYwcTgzIDAgMTQxLjUgNTguNVQ4ODAtNDgwcTAgODMtNTguNSAxNDEuNVQ2ODAtMjgwSDUyMFoiLz48L3N2Zz4=';
Editor.lightDarkLinkImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBzdHlsZT0iY29sb3Itc2NoZW1lOmxpZ2h0IGRhcms7IiBmaWxsPSJsaWdodC1kYXJrKCMwMDAwMDAsI2ZmZmZmZikiPjxwYXRoIGQ9Ik00NDAtMjgwSDI4MHEtODMgMC0xNDEuNS01OC41VDgwLTQ4MHEwLTgzIDU4LjUtMTQxLjVUMjgwLTY4MGgxNjB2ODBIMjgwcS01MCAwLTg1IDM1dC0zNSA4NXEwIDUwIDM1IDg1dDg1IDM1aDE2MHY4MFpNMzIwLTQ0MHYtODBoMzIwdjgwSDMyMFptMjAwIDE2MHYtODBoMTYwcTUwIDAgODUtMzV0MzUtODVxMC01MC0zNS04NXQtODUtMzVINTIwdi04MGgxNjBxODMgMCAxNDEuNSA1OC41VDg4MC00ODBxMCA4My01OC41IDE0MS41VDY4MC0yODBINTIwWiIvPjwvc3ZnPg==';
Editor.tooltipImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMWYxZjFmIj48cGF0aCBkPSJNNDQwLTI4MGg4MHYtMjQwaC04MHYyNDBabTY4LjUtMzMxLjVRNTIwLTYyMyA1MjAtNjQwdC0xMS41LTI4LjVRNDk3LTY4MCA0ODAtNjgwdC0yOC41IDExLjVRNDQwLTY1NyA0NDAtNjQwdDExLjUgMjguNVE0NjMtNjAwIDQ4MC02MDB0MjguNS0xMS41Wk00ODAtODBxLTgzIDAtMTU2LTMxLjVUMTk3LTE5N3EtNTQtNTQtODUuNS0xMjdUODAtNDgwcTAtODMgMzEuNS0xNTZUMTk3LTc2M3E1NC01NCAxMjctODUuNVQ0ODAtODgwcTgzIDAgMTU2IDMxLjVUNzYzLTc2M3E1NCA1NCA4NS41IDEyN1Q4ODAtNDgwcTAgODMtMzEuNSAxNTZUNzYzLTE5N3EtNTQgNTQtMTI3IDg1LjVUNDgwLTgwWm0wLTgwcTEzNCAwIDIyNy05M3Q5My0yMjdxMC0xMzQtOTMtMjI3dC0yMjctOTNxLTEzNCAwLTIyNyA5M3QtOTMgMjI3cTAgMTM0IDkzIDIyN3QyMjcgOTNabTAtMzIwWiIvPjwvc3ZnPg==';
Editor.lightDarkTooltipImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBzdHlsZT0iY29sb3Itc2NoZW1lOmxpZ2h0IGRhcms7IiBmaWxsPSJsaWdodC1kYXJrKCMwMDAwMDAsI2ZmZmZmZikiPjxwYXRoIGQ9Ik00NDAtMjgwaDgwdi0yNDBoLTgwdjI0MFptNjguNS0zMzEuNVE1MjAtNjIzIDUyMC02NDB0LTExLjUtMjguNVE0OTctNjgwIDQ4MC02ODB0LTI4LjUgMTEuNVE0NDAtNjU3IDQ0MC02NDB0MTEuNSAyOC41UTQ2My02MDAgNDgwLTYwMHQyOC41LTExLjVaTTQ4MC04MHEtODMgMC0xNTYtMzEuNVQxOTctMTk3cS01NC01NC04NS41LTEyN1Q4MC00ODBxMC04MyAzMS41LTE1NlQxOTctNzYzcTU0LTU0IDEyNy04NS41VDQ4MC04ODBxODMgMCAxNTYgMzEuNVQ3NjMtNzYzcTU0IDU0IDg1LjUgMTI3VDg4MC00ODBxMCA4My0zMS41IDE1NlQ3NjMtMTk3cS01NCA1NC0xMjcgODUuNVQ0ODAtODBabTAtODBxMTM0IDAgMjI3LTkzdDkzLTIyN3EwLTEzNC05My0yMjd0LTIyNy05M3EtMTM0IDAtMjI3IDkzdC05MyAyMjdxMCAxMzQgOTMgMjI3dDIyNyA5M1ptMC0zMjBaIi8+PC9zdmc+';
Editor.imageImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTEyMHEtMzMgMC01Ni41LTIzLjVUMTIwLTIwMHYtNTYwcTAtMzMgMjMuNS01Ni41VDIwMC04NDBoNTYwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2NTYwcTAgMzMtMjMuNSA1Ni41VDc2MC0xMjBIMjAwWm0wLTgwaDU2MHYtNTYwSDIwMHY1NjBabTQwLTgwaDQ4MEw1NzAtNDgwIDQ1MC0zMjBsLTkwLTEyMC0xMjAgMTYwWm0tNDAgODB2LTU2MCA1NjBaIi8+PC9zdmc+';
Editor.horizontalRuleImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTYwLTQ0MHYtODBoNjQwdjgwSDE2MFoiLz48L3N2Zz4=';
Editor.tableImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTEyMHEtMzMgMC01Ni41LTIzLjVUMTIwLTIwMHYtNTYwcTAtMzMgMjMuNS01Ni41VDIwMC04NDBoNTYwcTMzIDAgNTYuNSAyMy41VDg0MC03NjB2NTYwcTAgMzMtMjMuNSA1Ni41VDc2MC0xMjBIMjAwWm0yNDAtMjQwSDIwMHYxNjBoMjQwdi0xNjBabTgwIDB2MTYwaDI0MHYtMTYwSDUyMFptLTgwLTgwdi0xNjBIMjAwdjE2MGgyNDBabTgwIDBoMjQwdi0xNjBINTIwdjE2MFpNMjAwLTY4MGg1NjB2LTgwSDIwMHY4MFoiLz48L3N2Zz4=';
Editor.spacingImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjQwLTgwIDgwLTI0MGwxNjAtMTYwIDU3IDU2LTY0IDY0aDQ5NGwtNjMtNjQgNTYtNTYgMTYwIDE2MEw3MjAtODBsLTU3LTU2IDY0LTY0SDIzM2w2MyA2NC01NiA1NlptMzYtMzYwIDE2NC00NDBoODBsMTY0IDQ0MGgtNzZsLTM4LTExMkgzOTJsLTQwIDExMmgtNzZabTEzOC0xNzZoMTMybC02NC0xODJoLTRsLTY0IDE4MloiLz48L3N2Zz4=';
Editor.addColumnLeftImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNODAwLTIwMHYtNTYwSDU2MHY1NjBoMjQwWm0tNjQwIDgwdi0xNjBoODB2ODBoMjQwdi01NjBIMjQwdjgwaC04MHYtMTYwaDcyMHY3MjBIMTYwWm0zMjAtMzYwWm04MCAwaC04MCA4MFptMCAwWk0xNjAtMzYwdi04MEg4MHYtODBoODB2LTgwaDgwdjgwaDgwdjgwaC04MHY4MGgtODBaIi8+PC9zdmc+';
Editor.addColumnRightImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMTYwLTc2MHY1NjBoMjQwdi01NjBIMTYwWk04MC0xMjB2LTcyMGg3MjB2MTYwaC04MHYtODBINDgwdjU2MGgyNDB2LTgwaDgwdjE2MEg4MFptNDAwLTM2MFptLTgwIDBoODAtODBabTAgMFptMzIwIDEyMHYtODBoLTgwdi04MGg4MHYtODBoODB2ODBoODB2ODBoLTgwdjgwaC04MFoiLz48L3N2Zz4=';
Editor.removeColumnImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCkgc2NhbGUoMSwtMSkiPjxwYXRoIGQ9Ik01NjAtMjgwSDEyMHYtNDAwaDcyMHYxMjBoLTgwdi00MEgyMDB2MjQwaDM2MHY4MFptLTM2MC04MHYtMjQwIDI0MFptNDQwIDEwNCA4NC04NC04NC04NCA1Ni01NiA4NCA4NCA4NC04NCA1NiA1Ni04MyA4NCA4MyA4NC01NiA1Ni04NC04My04NCA4My01Ni01NloiLz48L3N2Zz4=';
Editor.addRowAboveImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTE2MGg1NjB2LTI0MEgyMDB2MjQwWm02NDAgODBIMTIwdi03MjBoMTYwdjgwaC04MHYyNDBoNTYwdi0yNDBoLTgwdi04MGgxNjB2NzIwWk00ODAtNDgwWm0wIDgwdi04MCA4MFptMCAwWm0tNDAtMjQwdi04MGgtODB2LTgwaDgwdi04MGg4MHY4MGg4MHY4MGgtODB2ODBoLTgwWiIvPjwvc3ZnPg==';
Editor.addRowBelowImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMjAwLTU2MGg1NjB2LTI0MEgyMDB2MjQwWm0tODAgNDAwdi03MjBoNzIwdjcyMEg2ODB2LTgwaDgwdi0yNDBIMjAwdjI0MGg4MHY4MEgxMjBabTM2MC0zMjBabTAtODB2ODAtODBabTAgMFpNNDQwLTgwdi04MGgtODB2LTgwaDgwdi04MGg4MHY4MGg4MHY4MGgtODB2ODBoLTgwWiIvPjwvc3ZnPg==';
Editor.removeRowImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNTYwLTI4MEgxMjB2LTQwMGg3MjB2MTIwaC04MHYtNDBIMjAwdjI0MGgzNjB2ODBabS0zNjAtODB2LTI0MCAyNDBabTQ0MCAxMDQgODQtODQtODQtODQgNTYtNTYgODQgODQgODQtODQgNTYgNTYtODMgODQgODMgODQtNTYgNTYtODQtODMtODQgODMtNTYtNTZaIi8+PC9zdmc+';
Editor.autosizeImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDAtNDB2LTI0MGg4MHYtNDAwSDQwdi0yNDBoMjQwdjgwaDQwMHYtODBoMjQwdjI0MGgtODB2NDAwaDgwdjI0MEg2ODB2LTgwSDI4MHY4MEg0MFptMjQwLTE2MGg0MDB2LTgwaDgwdi00MDBoLTgwdi04MEgyODB2ODBoLTgwdjQwMGg4MHY4MFptMzItMTIwIDEzNi0zNjBoNjRsMTM2IDM2MGgtNjJsLTMyLTkySDQwOGwtMzIgOTJoLTY0Wm0xMTQtMTQ0aDEwOGwtNTItMTUwaC00bC01MiAxNTBaTTEyMC03NjBoODB2LTgwaC04MHY4MFptNjQwIDBoODB2LTgwaC04MHY4MFptMCA2NDBoODB2LTgwaC04MHY4MFptLTY0MCAwaDgwdi04MGgtODB2ODBabTgwLTY0MFptNTYwIDBabTAgNTYwWm0tNTYwIDBaIi8+PC9zdmc+';
Editor.checkmarkImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjJweCIgaGVpZ2h0PSIxOHB4IiB2ZXJzaW9uPSIxLjEiPjxwYXRoIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMCkiIGQ9Ik03LjE4MSwxNS4wMDdhMSwxLDAsMCwxLS43OTMtMC4zOTFMMy4yMjIsMTAuNUExLDEsMCwxLDEsNC44MDgsOS4yNzRMNy4xMzIsMTIuM2w2LjA0NC04Ljg2QTEsMSwwLDEsMSwxNC44Myw0LjU2OWwtNi44MjMsMTBhMSwxLDAsMCwxLS44LjQzN0g3LjE4MVoiIGZpbGw9IiMwMDAwMDAiLz48L3N2Zz4=';
Editor.swapImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNMzIwLTQ0MHYtMjg3TDIxNy02MjRsLTU3LTU2IDIwMC0yMDAgMjAwIDIwMC01NyA1Ni0xMDMtMTAzdjI4N2gtODBaTTYwMC04MCA0MDAtMjgwbDU3LTU2IDEwMyAxMDN2LTI4N2g4MHYyODdsMTAzLTEwMyA1NyA1Nkw2MDAtODBaIi8+PC9zdmc+';
Editor.copyImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNzYwLTIwMEgzMjBxLTMzIDAtNTYuNS0yMy41VDI0MC0yODB2LTU2MHEwLTMzIDIzLjUtNTYuNVQzMjAtOTIwaDI4MGwyNDAgMjQwdjQwMHEwIDMzLTIzLjUgNTYuNVQ3NjAtMjAwWk01NjAtNjQwdi0yMDBIMzIwdjU2MGg0NDB2LTM2MEg1NjBaTTE2MC00MHEtMzMgMC01Ni41LTIzLjVUODAtMTIwdi01NjBoODB2NTYwaDQ0MHY4MEgxNjBabTE2MC04MDB2MjAwLTIwMCA1NjAtNTYwWiIvPjwvc3ZnPg==';
Editor.doubleArrowUpImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJtMjk2LTIyNC01Ni01NiAyNDAtMjQwIDI0MCAyNDAtNTYgNTYtMTg0LTE4My0xODQgMTgzWm0wLTI0MC01Ni01NiAyNDAtMjQwIDI0MCAyNDAtNTYgNTYtMTg0LTE4My0xODQgMTgzWiIvPjwvc3ZnPg==';
Editor.doubleArrowDownImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDgwLTIwMCAyNDAtNDQwbDU2LTU2IDE4NCAxODMgMTg0LTE4MyA1NiA1Ni0yNDAgMjQwWm0wLTI0MEwyNDAtNjgwbDU2LTU2IDE4NCAxODMgMTg0LTE4MyA1NiA1Ni0yNDAgMjQwWiIvPjwvc3ZnPg==';
Editor.opacityImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMWYxZjFmIj48cGF0aCBkPSJNNDgwLTEyMHEtMTMzIDAtMjI2LjUtOTJUMTYwLTQzNnEwLTY1IDI1LTEyMS41VDI1NC02NThsMjI2LTIyMiAyMjYgMjIycTQ0IDQ0IDY5IDEwMC41VDgwMC00MzZxMCAxMzItOTMuNSAyMjRUNDgwLTEyMFpNMjQyLTQwMGg0NzRxMTItNzItMTMuNS0xMjNUNjUwLTYwMEw0ODAtNzY4IDMxMC02MDBxLTI3IDI2LTUzIDc3dC0xNSAxMjNaIi8+PC9zdmc+';
Editor.shareImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjMWYxZjFmIj48cGF0aCBkPSJNMjQwLTgwcS0zMyAwLTU2LjUtMjMuNVQxNjAtMTYwdi00MDBxMC0zMyAyMy41LTU2LjVUMjQwLTY0MGgxMjB2ODBIMjQwdjQwMGg0ODB2LTQwMEg2MDB2LTgwaDEyMHEzMyAwIDU2LjUgMjMuNVQ4MDAtNTYwdjQwMHEwIDMzLTIzLjUgNTYuNVQ3MjAtODBIMjQwWm0yMDAtMjQwdi00NDdsLTY0IDY0LTU2LTU3IDE2MC0xNjAgMTYwIDE2MC01NiA1Ny02NC02NHY0NDdoLTgwWiIvPjwvc3ZnPg==';

/**
 * All fill styles supported by rough.js.
 */
Editor.roughFillStyles = [{val: 'auto', dispName: 'Auto'}, {val: 'hachure', dispName: 'Hachure'},
	{val: 'solid', dispName: 'Solid'}, {val: 'zigzag', dispName: 'ZigZag'},
	{val: 'cross-hatch', dispName: 'Cross Hatch'}, {val: 'dashed', dispName: 'Dashed'},
	{val: 'zigzag-line', dispName: 'ZigZag Line'}];

/**
 * Fill styles for normal mode.
 */
Editor.fillStyles = [{val: 'auto', dispName: 'Auto'}, {val: 'hatch', dispName: 'Hatch'},
	{val: 'solid', dispName: 'Solid'}, {val: 'dots', dispName: 'Dots'}, 
	{val: 'cross-hatch', dispName: 'Cross Hatch'}, {val: 'dashed', dispName: 'Dashed'},
	{val: 'zigzag-line', dispName: 'ZigZag Line'}];

/**
 * List of supported custom themes.
 */
Editor.themes = [];

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.ctrlKey = (mxClient.IS_MAC) ? '⌘' : 'Ctrl';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.altKey = (mxClient.IS_MAC) ? '⌥' : 'Alt';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.shiftKey = (mxClient.IS_MAC) ? '⇧' : 'Shift';

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.hintOffset = 20;

/**
 * Delay in ms to show shape picker on hover over blue arrows.
 */
Editor.shapePickerHoverDelay = 300;

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.fitWindowBorders = null;

/**
 * Specifies if the diagram should be saved automatically if possible. Default
 * is true.
 */
Editor.popupsAllowed = window.urlParams != null? urlParams['noDevice'] != '1' : true;

/**
 * Specifies if the html and whiteSpace styles should be removed on inserted cells.
 */
Editor.simpleLabels = false;

/**
 * Specifies if unnecessary spans should be removed from HTML labels when
 * editing is stopped. Adjacent spans with compatible styles are merged
 * and redundant wrapper spans are unwrapped. Default is false.
 */
Editor.optimizeHtmlLabels = false;
	
/**
 * Specifies if the native clipboard is enabled. Blocked in iframes for possible sandbox attribute.
 * LATER: Check if actually blocked.
 */
Editor.enableNativeClipboard = window == window.top && navigator.clipboard != null &&
	navigator.clipboard.read != null;

/**
 * Dynamic change of dark mode for minimal and sketch theme.
 */
Editor.sketchMode = false;

/**
 * Dynamic change of dark mode for minimal and sketch theme.
 */
Editor.darkMode = false;

/**
 * Dynamic change of dark mode for minimal and sketch theme.
 */
Editor.currentTheme = uiTheme;

/**
 * Dynamic change of dark mode for minimal and sketch theme.
 */
Editor.darkColor = '#121212';

/**
 * Name of the variable to use for the dark color var in exported SVG.
 * Default is '--ge-dark-color'.
 */
Editor.darkColorVar = '--ge-dark-color';

/**
 * Label for the font size unit. Default is 'px'.
 */
Editor.fontSizeUnit = 'px';

/**
 * Delay for transitions in secons. Default in 0.1.
 */
Editor.transitionDelay = 0.1;

/**
 * Default unit for page sizes. Default is inches.
 */
Editor.pageSizeUnit = mxConstants.INCHES;

/**
 * Whether to remove EXIF metadata from pasted images. Default is true.
 */
Editor.removeImageMetadata = true;

/**
 * Whether to show the connect handle on selected vertices. Default is false.
 */
Editor.showConnectHandle = false;

/**
 * Whether to enable the inline toolbar. Default is true.
 */
Editor.enableInlineToolbar = true;

/**
 * Returns the current state of the dark mode.
 */
Editor.isDarkMode = function()
{
	return Editor.darkMode;
};

/**
 * Returns true if the given URL is a PNG data URL.
 */
Editor.isPngDataUrl = function(url)
{
	return url != null && url.substring(0, 15) == 'data:image/png;'
};

/**
 * Returns true if the given URL is a JPEG data URL.
 */
Editor.isJpgDataUrl = function(url)
{
	return url != null && (url.substring(0, 15) == 'data:image/jpg;' ||
		url.substring(0, 16) == 'data:image/jpeg;');
};

/**
 * Returns true if the given binary data is a PNG file.
 */
Editor.isPngData = function(data)
{
	return data.length > 8 && data.charCodeAt(0) == 137 && data.charCodeAt(1) == 80 &&
		data.charCodeAt(2) == 78 && data.charCodeAt(3) == 71 && data.charCodeAt(4) == 13 &&
		data.charCodeAt(5) == 10 && data.charCodeAt(6) == 26 && data.charCodeAt(7) == 10;
};

/**
 * Returns true if the given binary data is a JPEG file.
 */
Editor.isJpgData = function(data)
{
	return data.length > 2 && data.charCodeAt(0) == 255 && data.charCodeAt(1) == 216;
};

/**
 * Removes EXIF metadata from the given JPEG data URI and returns the cleaned data URI.
 */
Editor.stripImageMetadata = function(dataUri, enabled)
{
	if (dataUri != null && enabled &&
		(Editor.isJpgDataUrl(dataUri) ||
		Editor.isPngDataUrl(dataUri)))
	{
		var comma = dataUri.indexOf(',') + 1;
		var base64 = dataUri.substring(comma);
		
		// Workaround for invalid character error in Safari
		var binary = (window.atob && !mxClient.IS_SF) ?
			atob(base64) : Base64.decode(base64, true);
		var buffer = new ArrayBuffer(binary.length);

		// Ready bytes into buffer
		var bytes = new Uint8Array(buffer);
		
		for (var i = 0; i < binary.length; i++)
		{
			bytes[i] = binary.charCodeAt(i);
		}

		// Removes metadata for supported formats
		var result = null;

		try
		{
			if (Editor.isJpgData(binary))
			{
				result = Editor.stripJpgMetadata(buffer);
			}
			else if (Editor.isPngData(binary))
			{
				result = Editor.stripPngMetadata(buffer);
			}
		}
		catch (e)
		{
			// ignore
		}

		// Converts back to Base64
		if (result != null)
		{
			var newBase64 = '';

			for (var i = 0; i < result.length; i++)
			{
				newBase64 += String.fromCharCode(result[i]);
			}

			dataUri = dataUri.substring(0, comma) + btoa(newBase64);
		}
	}

	return dataUri;
};

/**
 * Removes EXIF metadata from the given JPEG data.
 */
Editor.stripJpgMetadata = function(buffer)
{
	var view = new DataView(buffer);
	var chunks = [];
	chunks.push(new Uint8Array(buffer, 0, 2)); // SOI
	var offset = 2;

	while (offset < buffer.byteLength - 1)
	{
		var marker = view.getUint16(offset);
		
		// SOS - Copies rest
		if (marker === 0xFFDA)
		{
			chunks.push(new Uint8Array(buffer, offset));
			break;
		}
		
		// Standalone markers
		if (marker >= 0xFFD0 && marker <= 0xFFD9)
		{
			chunks.push(new Uint8Array(buffer, offset, 2));
			offset += 2;
			continue;
		}
		
		var segmentLength = view.getUint16(offset + 2);
		
		// Skips APP1/APP2
		var isApp1 = marker === 0xFFE1;
		var isApp2 = marker === 0xFFE2;
		
		if (!isApp1 && !isApp2)
		{
			chunks.push(new Uint8Array(buffer, offset, 2 + segmentLength));
		}

		offset += 2 + segmentLength;
	}
	
	// Merges chunks
	var totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
	var result = new Uint8Array(totalLength);
	var pos = 0;

	for (var chunk of chunks)
	{
		result.set(chunk, pos);
		pos += chunk.length;
	}

	return result;
};

/**
 * Removes EXIF metadata from the given PNG data.
 */
Editor.stripPngMetadata = function(buffer)
{
	var view = new DataView(buffer);

	// Chunks to be removed
	var metadataChunks = new Set([
		'eXIf', // EXIF
		'tEXt', // Text
		'iTXt', // International text / XMP
		'zTXt', // Compressed text
		'iCCP', // ICC Profile
		'tIME', // Modification time
		// Optional chunks:
		// 'pHYs', // DPI info
		// 'hIST', // Histogram
		// 'sPLT', // Suggested palette
	]);

	var chunks = [];
	chunks.push(new Uint8Array(buffer, 0, 8)); // PNG signature

	var offset = 8;
	while (offset < buffer.byteLength)
	{
		var length = view.getUint32(offset);
		var type = String.fromCharCode(
			view.getUint8(offset + 4),
			view.getUint8(offset + 5),
			view.getUint8(offset + 6),
			view.getUint8(offset + 7))
		var chunkSize = 4 + 4 + length + 4; // length + type + data + CRC

		if (!metadataChunks.has(type))
		{
			chunks.push(new Uint8Array(buffer, offset, chunkSize));
		}

		offset += chunkSize;

		if (type === 'IEND')
		{
			break;
		}
	}

	// Merges chunks
	var totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
	var result = new Uint8Array(totalLength);
	var pos = 0;

	for (var chunk of chunks)
	{
		result.set(chunk, pos);
		pos += chunk.length;
	}

	return result;
};

/**
 * Converts HTML to plain text.
 */
Editor.convertHtmlToText = function(label)
{
	if (label != null)
	{
		var temp = document.createElement('div');
		temp.innerHTML = Graph.sanitizeHtml(label);

		return mxUtils.extractTextWithWhitespace(temp.childNodes)
	}
	else
	{
		return null;
	}
};

/**
 *
 */
Editor.extractGraphModelFromText = function(text)
{
	var start = text.indexOf('<mxGraphModel ');
	var end = text.indexOf('</mxGraphModel>');

	if (start < 0)
	{
		start = text.indexOf('<mxGraphModel>');
	}

	function trimStart(text)
	{
		var index = text.indexOf('```');

		if (index >= 0)
		{
			text = text.substring(text, 0, index + 6);
		}

		return text;
	};

	function trimEnd(text)
	{
		var index = text.lastIndexOf('```');

		if (index >= 0)
		{
			text = text.substring(index + 3);
		}

		return text;
	};
	
	if (start >= 0 && end > start)
	{
		return [mxUtils.trim(trimStart(text.substring(0, start))),
			text.substring(start, end + 15),
			mxUtils.trim(trimEnd(text.substring(end + 15)))];
	}
	else
	{
		return [text, '', ''];
	}
};

/**
 * Extracts the XML from the compressed or non-compressed text chunk.
 */
Editor.extractGraphModelFromPng = function(data)
{
	var result = null;
	
	try
	{
		var base64 = data.substring(data.indexOf(',') + 1);

		// Workaround for invalid character error in Safari
		var binary = (window.atob && !mxClient.IS_SF) ? atob(base64) : Base64.decode(base64, true);
		
		EditorUi.parsePng(binary, mxUtils.bind(this, function(pos, type, length)
		{
			var value = binary.substring(pos + 8, pos + 8 + length);
			
			if (type == 'zTXt')
			{
				var idx = value.indexOf(String.fromCharCode(0));
				
				if (value.substring(0, idx) == 'mxGraphModel')
				{
					// Workaround for Java URL Encoder using + for spaces, which isn't compatible with JS
					var xmlData = pako.inflateRaw(Graph.stringToArrayBuffer(
						value.substring(idx + 2)), {to: 'string'}).replace(/\+/g,' ');
					
					if (xmlData != null && xmlData.length > 0)
					{
						result = xmlData;
					}
				}
			}
			// Uncompressed section is normally not used
			else if (type == 'tEXt')
			{
				var vals = value.split(String.fromCharCode(0));
				
				if (vals.length > 1 && (vals[0] == 'mxGraphModel' ||
					vals[0] == 'mxfile'))
				{
					result = vals[1];
				}
			}
			
			if (result != null || type == 'IDAT')
			{
				// Stops processing the file as our text chunks
				// are always placed before the data section
				return true;
			}
		}));
	}
	catch (e)
	{
		// ignores decoding errors
	}
	
	if (result != null && result.charAt(0) == '%')
	{
		result = decodeURIComponent(result);
	}
	
	// Workaround for double encoded content
	if (result != null && result.charAt(0) == '%')
	{
		result = decodeURIComponent(result);
	}
	
	return result;
};

/**
 * Parses a camel case name with an optional trailing number and returns a
 * user-friendly label.
 */
Editor.getLabelForStylename = function(name)
{
	var m = name.match(/^([A-Za-z]*)(\d*)$/);

	if (m != null && m.length > 1)
	{
		var words = mxUtils.trim(m[1]
			.replace(/([a-z])([A-Z])/g, '$1 $2')
			.replace(/\b\w/g, function(token)
			{
				return token.toUpperCase();
			})
			.replace(/Color[s]?/g, ''));
		var num = (m[2].length > 0 ?
			' (' +  m[2] + ')' : '');
		name = mxUtils.trim(words + num);
	}
	
	return name;
};

/**
 * Soundex algorithm for strings.
 * See https://www.codedrome.com/the-soundex-algorithm-in-javascript/
 */
Editor.soundex = function(name)
{
	if (name == null || name.length == 0)
	{
		return '';
	}
	else
	{
		var s = [];
		var si = 1;
		var c;

		// Changed: s maps to 0 not 2 to ignore plurals
		//              ABCDEFGHIJKLMNOPQRSTUVWXYZ
		var mappings = '01230120022455012603010202';

		s[0] = name[0].toUpperCase();

		for(var i = 1, l = name.length; i < l; i++)
		{
			c = (name[i].toUpperCase()).charCodeAt(0) - 65;

			if(c >= 0 && c <= 25)
			{
				if(mappings[c] != '0')
				{
					if(mappings[c] != s[si-1])
					{
						s[si] = mappings[c];
						si++;
					}

					if(si > 3)
					{
						break;
					}
				}
			}
		}

		if(si <= 3)
		{
			while(si <= 3)
			{
				s[si] = '0';
				si++;
			}
		}

		return s.join('');
	}
};

/**
 * Selects the given part of the input element.
 */
Editor.selectFilename = function(input)
{
	var end = input.value.lastIndexOf('.');

	if (end > 0)
	{
		var ext = input.value.substring(end + 1);

		if (ext != 'drawio')
		{
			if (mxUtils.indexOf(['png', 'svg', 'html', 'xml', 'pdf'], ext) >= 0)
			{
				var temp = input.value.lastIndexOf('.drawio.', end);

				if (temp > 0)
				{
					end = temp;
				}
			}
		}
	}
	
	end = (end > 0) ? end : input.value.length;
	Editor.selectSubstring(input, 0, end);
};

/**
 * Selects the given part of the input element.
 */
Editor.selectSubstring = function(input, startPos, endPos)
{
	input.focus();

	if (typeof input.selectionStart != 'undefined')
	{
		input.selectionStart = startPos;
		input.selectionEnd = endPos;
	}
	else if (document.selection && document.selection.createRange)
	{
		// IE branch
		input.select();
		var range = document.selection.createRange();
		range.collapse(true);
		range.moveEnd('character', endPos);
		range.moveStart('character', startPos);
		range.select();
	}
};

/**
 * 
 */
Editor.toUnit = function(value, unit)
{
	if (unit == mxConstants.INCHES)
	{
		return Math.round(value * 100 / mxConstants.PIXELS_PER_INCH) / 100;
	}
	else if (unit == mxConstants.MILLIMETERS)
	{
		return  Math.round(value * 100 / mxConstants.PIXELS_PER_MM) / 100;
	}
	else if (unit == mxConstants.METERS)
	{
		return  Math.round(value * 1000 / (mxConstants.PIXELS_PER_MM * 1000)) / 1000;
	}
	else
	{
		return Math.round(value);
	}
};

/**
 * 
 */
Editor.fromUnit = function(value, unit)
{
	if (unit == mxConstants.INCHES)
	{
		return Math.round(value * mxConstants.PIXELS_PER_INCH);
	}
	else if (unit == mxConstants.MILLIMETERS)
	{
		return Math.round(value * mxConstants.PIXELS_PER_MM);
	}
	else if (unit == mxConstants.METERS)
	{
		return Math.round(value * mxConstants.PIXELS_PER_MM * 1000);
	}
	else
	{
		return Math.round(value);
	}
};

/**
 * Editor inherits from mxEventSource
 */
mxUtils.extend(Editor, mxEventSource);

/**
 * Stores initial state of mxClient.NO_FO.
 */
Editor.prototype.originalNoForeignObject = mxClient.NO_FO;

/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.prototype.transparentImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7' :
	IMAGE_PATH + '/transparent.gif';

/**
 * Specifies if the canvas should be extended in all directions. Default is true.
 */
Editor.prototype.extendCanvas = true;

/**
 * Specifies if the app should run in chromeless mode. Default is false.
 * This default is only used if the contructor argument is null.
 */
Editor.prototype.chromeless = false;

/**
 * Specifies the order of OK/Cancel buttons in dialogs. Default is true.
 * Cancel first is used on Macs, Windows/Confluence uses cancel last.
 */
Editor.prototype.cancelFirst = true;

/**
 * Specifies if the editor is enabled. Default is true.
 */
Editor.prototype.enabled = true;

/**
 * Contains the name which was used for the last save. Default value is null.
 */
Editor.prototype.filename = null;

/**
 * Contains the current modified state of the diagram. This is false for
 * new diagrams and after the diagram was saved.
 */
Editor.prototype.modified = false;

/**
 * Specifies if the diagram should be saved automatically if possible. Default
 * is true.
 */
Editor.prototype.autosave = true;

/**
 * Specifies the app name. Default is document.title.
 */
Editor.prototype.appName = document.title;

/**
 * 
 */
Editor.prototype.editBlankUrl = window.location.origin + window.location.pathname;

/**
 * Default value for the graph container overflow style.
 */
Editor.prototype.defaultGraphOverflow = 'hidden';

/**
 * Initializes the environment.
 */
Editor.prototype.init = function() { };

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.isChromelessView = function()
{
	return this.chromeless;
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.setAutosave = function(value)
{
	this.autosave = value;
	this.fireEvent(new mxEventObject('autosaveChanged'));
};

/**
 * 
 */
Editor.prototype.getEditBlankUrl = function(params)
{
	return this.editBlankUrl + params;
}

/**
 * 
 */
Editor.prototype.editAsNew = function(xml, title, lightbox, pageId)
{
	var p = (title != null) ? '?title=' + encodeURIComponent(title) : '';
	
	if (lightbox)
	{
		p += ((p.length > 0) ? '&' : '?') + 'lightbox=1';
	}
	else if (urlParams['ui'] != null)
	{
		p += ((p.length > 0) ? '&' : '?') + 'ui=' + urlParams['ui'];
	}
	
	if (pageId != null)
	{
		p += ((p.length > 0) ? '&' : '?') + 'page-id=' + pageId;
	}
	
	if (!navigator.standalone &&
		typeof window.postMessage !== 'undefined')
	{
		var wnd = null;
		
		var l = mxUtils.bind(this, function(evt)
		{
			if (evt.data == 'ready' && evt.source == wnd)
			{
				mxEvent.removeListener(window, 'message', l);
				wnd.postMessage(xml, '*');
			}
		});

		// Uses transient hash for URL parameters
		var tokens = p.substring(1).split('&');
		var json = {'client': 1};

		for (var i = 0; i < tokens.length; i++)
		{
			var keyValue = tokens[i].split('=');
			json[keyValue[0]] = keyValue[1] || '';
		}
		
		mxEvent.addListener(window, 'message', l);
		wnd = this.graph.openLink(this.getEditBlankUrl('') +
			'#P' + encodeURIComponent(JSON.stringify(json)),
			null, true);
	}
	else
	{
		this.graph.openLink(this.getEditBlankUrl(p) +
			'#R' + encodeURIComponent(xml));
	}
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.createGraph = function(themes, model)
{
	var graph = new Graph(null, model, null, null, themes);
	graph.transparentBackground = false;
	
	// Disables CSS transforms in Safari in chromeless mode
	var graphIsCssTransformsSupported = graph.isCssTransformsSupported;
	var self = this;

	graph.isCssTransformsSupported = function()
	{
		return graphIsCssTransformsSupported.apply(this, arguments) &&
			(!self.chromeless || !mxClient.IS_SF);
	};

	// Opens all links in a new window while editing
	if (!this.chromeless)
	{
		graph.isBlankLink = function(href)
		{
			return !this.isExternalProtocol(href);
		};
	}
	
	return graph;
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.resetGraph = function()
{
	this.graph.gridEnabled = this.graph.defaultGridEnabled && (!this.isChromelessView() || urlParams['grid'] == '1');
	this.graph.graphHandler.guidesEnabled = true;
	this.graph.setTooltips(true);
	this.graph.setConnectable(this.graph.defaultConnectable);
	this.graph.connectionArrowsEnabled = this.graph.defaultConnectionArrowsEnabled;
	this.graph.foldingEnabled = this.graph.defaultFoldingEnabled;
	this.graph.scrollbars = this.graph.defaultScrollbars;
	this.graph.pageVisible = this.graph.defaultPageVisible;
	this.graph.pageBreaksVisible = this.graph.pageVisible; 
	this.graph.preferPageSize = this.graph.pageBreaksVisible;
	this.graph.background = null;
	this.graph.pageScale = mxGraph.prototype.pageScale;
	this.graph.pageFormat = mxGraph.prototype.pageFormat;
	this.graph.currentScale = 1;
	this.graph.currentTranslate.x = 0;
	this.graph.currentTranslate.y = 0;
	this.updateGraphComponents();
	this.graph.view.setScale(1);
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.readGraphState = function(node)
{
	// Preserve original XML attribute values for settings overridden by
	// URL parameters or config defaults so getGraphXml can write them back
	// instead of persisting the forced runtime state.
	this.savedGraphState = {};

	if (Editor.preserveViewState)
	{
		var dx = node.getAttribute('dx');
		var dy = node.getAttribute('dy');

		if (dx != null) this.savedGraphState.dx = dx;
		if (dy != null) this.savedGraphState.dy = dy;
	}

	var grid = node.getAttribute('grid');

	if (grid == null || grid == '')
	{
		grid = this.graph.defaultGridEnabled ? '1' : '0';
	}

	if (urlParams['grid'] != null)
	{
		this.savedGraphState.grid = grid;
	}

	this.graph.gridEnabled = (urlParams['grid'] != null ? urlParams['grid'] != '0' : grid != '0') &&
		(!this.isChromelessView() || urlParams['grid'] == '1');
	this.graph.gridSize = parseFloat(node.getAttribute('gridSize')) || mxGraph.prototype.gridSize;
	this.graph.graphHandler.guidesEnabled = node.getAttribute('guides') != '0';
	this.graph.setTooltips(node.getAttribute('tooltips') != '0');
	var connect = node.getAttribute('connect');

	if (connect != null && Editor.config != null && Editor.config.defaultConnectable != null)
	{
		this.savedGraphState.connect = connect;
	}

	this.graph.setConnectable(connect != null &&
		(Editor.config == null || Editor.config.defaultConnectable == null) ?
		connect != '0' : this.graph.defaultConnectable);

	var arrows = node.getAttribute('arrows');

	if (arrows != null && Editor.config != null && Editor.config.defaultConnectionArrowsEnabled != null)
	{
		this.savedGraphState.arrows = arrows;
	}

	this.graph.connectionArrowsEnabled = arrows != null &&
		(Editor.config == null || Editor.config.defaultConnectionArrowsEnabled == null) ?
		arrows != '0' : this.graph.defaultConnectionArrowsEnabled;
	var fold = node.getAttribute('fold');

	if (fold != null && Editor.config != null && Editor.config.defaultFoldingEnabled != null)
	{
		this.savedGraphState.fold = fold;
	}

	this.graph.foldingEnabled = fold != null &&
		(Editor.config == null || Editor.config.defaultFoldingEnabled == null) ?
		fold != '0' : this.graph.defaultFoldingEnabled;

	if (this.isChromelessView() && this.graph.foldingEnabled)
	{
		this.graph.foldingEnabled = urlParams['nav'] == '1';
		this.graph.cellRenderer.forceControlClickHandler = this.graph.foldingEnabled;
	}

	var ps = parseFloat(node.getAttribute('pageScale'));

	if (!isNaN(ps) && ps > 0)
	{
		this.graph.pageScale = ps;
	}
	else
	{
		this.graph.pageScale = mxGraph.prototype.pageScale;
	}

	if (!this.graph.isLightboxView() && !this.graph.isViewer())
	{
		if (urlParams['pv'] != null)
		{
			var pv = node.getAttribute('page');
			this.savedGraphState.page = pv;
			this.graph.pageVisible = urlParams['pv'] != '0';
		}
		else
		{
			var pv = node.getAttribute('page');

			if (pv != null)
			{
				this.graph.pageVisible = (pv != '0');
			}
			else
			{
				this.graph.pageVisible = this.graph.defaultPageVisible;
			}
		}
	}
	else
	{
		this.graph.pageVisible = false;
	}
	
	this.graph.pageBreaksVisible = this.graph.pageVisible; 
	this.graph.preferPageSize = this.graph.pageBreaksVisible;
	
	var pw = parseFloat(node.getAttribute('pageWidth'));
	var ph = parseFloat(node.getAttribute('pageHeight'));
	
	if (!isNaN(pw) && !isNaN(ph))
	{
		this.graph.pageFormat = new mxRectangle(0, 0, pw, ph);
	}

	// Loads the persistent state settings
	var bg = node.getAttribute('background');
	
	if (bg != null && bg.length > 0)
	{
		this.graph.background = bg;
	}
	else
	{
		this.graph.background = null;
	}
};

/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.setGraphXml = function(node)
{
	if (node != null)
	{
		var dec = new mxCodec(node.ownerDocument);
	
		if (node.nodeName == 'mxGraphModel')
		{
			this.graph.model.beginUpdate();
			
			try
			{
				this.graph.model.clear();
				this.graph.view.scale = 1;
				this.readGraphState(node);
				this.updateGraphComponents();
				dec.decode(node, this.graph.getModel());
			}
			finally
			{
				this.graph.model.endUpdate();
			}
		}
		else if (node.nodeName == 'root')
		{
			this.resetGraph();
			
			// Workaround for invalid XML output in Firefox 20 due to bug in mxUtils.getXml
			var wrapper = dec.document.createElement('mxGraphModel');
			wrapper.appendChild(node);
			
			dec.decode(wrapper, this.graph.getModel());
			this.updateGraphComponents();
		}
		else
		{
			throw { 
			    message: mxResources.get('cannotOpenFile'), 
			    node: node,
			    toString: function() { return this.message; }
			};
		}
	}
	else
	{
		this.resetGraph();
		this.graph.model.clear();
	}
	
	this.fireEvent(new mxEventObject('resetGraphView'));
};

/**
 * Returns the XML node that represents the current diagram.
 */
Editor.prototype.getGraphXml = function(ignoreSelection)
{
	ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
	var node = null;
	
	if (ignoreSelection)
	{
		var enc = new mxCodec(mxUtils.createXmlDocument());
		node = enc.encode(this.graph.getModel());
		enc.document.appendChild(node);
	}
	else
	{
		node = this.graph.encodeCells(mxUtils.sortCells(
			this.graph.model.getTopmostCells(
			this.graph.getSelectionCells())));
	}

	var saved = this.savedGraphState || {};

	if (saved.dx != null || saved.dy != null)
	{
		if (saved.dx != null) node.setAttribute('dx', saved.dx);
		if (saved.dy != null) node.setAttribute('dy', saved.dy);
	}
	else if (this.graph.view.translate.x != 0 || this.graph.view.translate.y != 0)
	{
		node.setAttribute('dx', Math.round(this.graph.view.translate.x * 100) / 100);
		node.setAttribute('dy', Math.round(this.graph.view.translate.y * 100) / 100);
	}
	node.setAttribute('grid', saved.grid != null ? saved.grid : (this.graph.isGridEnabled()) ? '1' : '0');
	node.setAttribute('gridSize', this.graph.gridSize);
	node.setAttribute('guides', (this.graph.graphHandler.guidesEnabled) ? '1' : '0');
	node.setAttribute('tooltips', (this.graph.tooltipHandler.isEnabled()) ? '1' : '0');
	node.setAttribute('connect', saved.connect != null ? saved.connect : (this.graph.connectionHandler.isEnabled()) ? '1' : '0');
	node.setAttribute('arrows', saved.arrows != null ? saved.arrows : (this.graph.connectionArrowsEnabled) ? '1' : '0');
	node.setAttribute('fold', saved.fold != null ? saved.fold : (this.graph.foldingEnabled) ? '1' : '0');
	node.setAttribute('page', saved.page != null ? saved.page : (this.graph.pageVisible) ? '1' : '0');
	node.setAttribute('pageScale', this.graph.pageScale);
	node.setAttribute('pageWidth', this.graph.pageFormat.width);
	node.setAttribute('pageHeight', this.graph.pageFormat.height);

	if (this.graph.background != null)
	{
		node.setAttribute('background', this.graph.background);
	}
	
	return node;
};

/**
 * Keeps the graph container in sync with the persistent graph state
 */
Editor.prototype.updateGraphComponents = function()
{
	var graph = this.graph;
	
	if (graph.container != null)
	{
		graph.view.validateBackground();
		graph.container.style.overflow = (graph.scrollbars) ?
			'auto' : this.defaultGraphOverflow;
		this.fireEvent(new mxEventObject('updateGraphComponents'));
	}
};

/**
 * Sets the modified flag.
 */
Editor.prototype.setModified = function(value)
{
	this.modified = value;
};

/**
 * Sets the filename.
 */
Editor.prototype.setFilename = function(value)
{
	this.filename = value;
};

/**
 * Creates and returns a new undo manager.
 */
Editor.prototype.createUndoManager = function()
{
	var graph = this.graph;
	var undoMgr = new mxUndoManager();

	this.undoListener = function(sender, evt)
	{
		undoMgr.undoableEditHappened(evt.getProperty('edit'));
	};
	
    // Installs the command history
	var listener = mxUtils.bind(this, function(sender, evt)
	{
		this.undoListener.apply(this, arguments);
	});
	
	graph.getModel().addListener(mxEvent.UNDO, listener);
	graph.getView().addListener(mxEvent.UNDO, listener);

	// Keeps the selection in sync with the history
	var undoHandler = function(sender, evt)
	{
		var changes = evt.getProperty('edit').changes;
		var cand = graph.getSelectionCellsForChanges(changes);
		var scrolled = false;
		
		if (cand.length > 0)
		{
			var cells = [];
			
			for (var i = 0; i < cand.length; i++)
			{
				if (graph.view.getState(cand[i]) != null)
				{
					cells.push(cand[i]);

					if (!scrolled)
					{
						graph.scrollCellToVisible(cand[i]);
						scrolled = true;
					}
				}
			}
			
			graph.setSelectionCells(cells);
		}
	};
	
	undoMgr.addListener(mxEvent.UNDO, undoHandler);
	undoMgr.addListener(mxEvent.REDO, undoHandler);

	return undoMgr;
};

/**
 * Adds basic stencil set (no namespace).
 */
Editor.prototype.initStencilRegistry = function() { };

/**
 * Creates and returns a new undo manager.
 */
Editor.prototype.destroy = function()
{
	if (this.graph != null)
	{
		this.graph.destroy();
		this.graph = null;
	}
};

/**
 * Class for asynchronously opening a new window and loading a file at the same
 * time. This acts as a bridge between the open dialog and the new editor.
 */
OpenFile = function(done)
{
	this.producer = null;
	this.consumer = null;
	this.done = done;
	this.args = null;
};

/**
 * Registers the editor from the new window.
 */
OpenFile.prototype.setConsumer = function(value)
{
	this.consumer = value;
	this.execute();
};

/**
 * Sets the data from the loaded file.
 */
OpenFile.prototype.setData = function()
{
	this.args = arguments;
	this.execute();
};

/**
 * Displays an error message.
 */
OpenFile.prototype.error = function(msg)
{
	this.cancel(true);
	mxUtils.alert(msg);
};

/**
 * Consumes the data.
 */
OpenFile.prototype.execute = function()
{
	if (this.consumer != null && this.args != null)
	{
		this.cancel(false);
		this.consumer.apply(this, this.args);
	}
};

/**
 * Cancels the operation.
 */
OpenFile.prototype.cancel = function(cancel)
{
	if (this.done != null)
	{
		this.done((cancel != null) ? cancel : true);
	}
};

/**
 * Basic dialogs that are available in the viewer (print dialog).
 */
function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transparent, minSize, ignoreBgClick)
{
	this.editorUi = editorUi;

	if (this.bg == null)
	{
		this.bg = editorUi.createDiv('geBackground');
	}

	// document.body can be null in edge cases (e.g. during page teardown);
	// skip the appendChild calls so the dialog construction does not crash
	if (modal && document.body != null)
	{
		document.body.appendChild(this.bg);
	}

	var div = editorUi.createDiv(transparent? 'geTransDialog' : 'geDialog');
	div.style.width = (w + 48) + 'px';

	if (h != null)
	{
		div.style.height = (h + 48) + 'px';
	}

	if (urlParams['embedInline'] == '1' && !Editor.inlineFullscreen &&
		editorUi.embedViewport != null)
	{
		div.style.left = (editorUi.embedViewport.x + editorUi.embedViewport.width / 2) + 'px';
		div.style.top = (editorUi.embedViewport.y + editorUi.embedViewport.height / 2) + 'px';
	}

	div.appendChild(elt);

	if (document.body != null)
	{
		document.body.appendChild(div);
	}

	if (h == null)
	{
		div.style.height = (elt.scrollHeight + 48) + 'px';
	}
	
	if (closable)
	{
		var closeImg = document.createElement('div');
		closeImg.className = 'geButton';
		closeImg.setAttribute('title', mxResources.get('close'));
		closeImg.style.backgroundImage = 'url(' + Editor.crossImage + ')';
		closeImg.style.position = 'absolute';
		closeImg.style.top = '0px';
		closeImg.style.right = '0px';
		
		mxEvent.addListener(closeImg, 'click', mxUtils.bind(this, function()
		{
			editorUi.hideDialog(true);
		}));
		
		div.appendChild(closeImg);
		
		if (!ignoreBgClick)
		{
			var mouseDownSeen = false;
			
			mxEvent.addGestureListeners(this.bg, mxUtils.bind(this, function(evt)
			{
				mouseDownSeen = true;
			}), null, mxUtils.bind(this, function(evt)
			{
				if (mouseDownSeen)
				{
					editorUi.hideDialog(true);
					mouseDownSeen = false;
				}
			}));
		}
	}
	
	this.onDialogClose = onClose;
	this.container = div;

	if (minSize != null)
	{
		this.addResizeHandler(minSize);
	}
	
	editorUi.editor.fireEvent(new mxEventObject('showDialog'));
};

/**
 * 
 */
Dialog.prototype.noColorImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkEzRDlBMUUwODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkEzRDlBMUUxODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTNEOUExREU4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTNEOUExREY4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5xh3fmAAAABlBMVEX////MzMw46qqDAAAAGElEQVR42mJggAJGKGAYIIGBth8KAAIMAEUQAIElnLuQAAAAAElFTkSuQmCC';

/**
 * 
 */
Dialog.prototype.closeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEV7mr3///+wksspAAAAAnRSTlP/AOW3MEoAAAAdSURBVAgdY9jXwCDDwNDRwHCwgeExmASygSL7GgB12QiqNHZZIwAAAABJRU5ErkJggg==';

/**
 * 
 */
Dialog.prototype.clearImage = 'data:image/gif;base64,R0lGODlhDQAKAIABAMDAwP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUIzOEM1NzI4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUIzOEM1NzM4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QjM4QzU3MDg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QjM4QzU3MTg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAAEALAAAAAANAAoAAAIXTGCJebD9jEOTqRlttXdrB32PJ2ncyRQAOw==';

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.getDocumentSize = function()
{
	return mxUtils.getDocumentSize();
};

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.getPosition = function(left, top)
{
	return new mxPoint(left, top);
};

/**
 * Adds a resize handler to the dialog.
 */
Dialog.prototype.addResizeHandler = function(minSize)
{
	var resize = document.createElement('img');
	resize.setAttribute('src', mxWindow.prototype.resizeImage);
	resize.style.cursor = 'nwse-resize';
	resize.style.position = 'absolute';
	resize.style.bottom = '0px';
	resize.style.right = '0px';
	resize.style.zIndex = '2';

	var startX = null;
	var startY = null;
	var width = null;
	var height = null;
	
	var start = mxUtils.bind(this, function(evt)
	{
		startX = mxEvent.getClientX(evt);
		startY = mxEvent.getClientY(evt);
		width = parseInt(this.container.style.width);
		height = parseInt(this.container.style.height);
		mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
		mxEvent.consume(evt);
	});

	// Adds a temporary pair of listeners to intercept
	// the gesture event in the document
	var dragHandler = mxUtils.bind(this, function(evt)
	{
		if (startX != null && startY != null)
		{
			var dx = mxEvent.getClientX(evt) - startX;
			var dy = mxEvent.getClientY(evt) - startY;
			this.container.style.width = Math.max(minSize.width, (width + 2 * dx)) + 'px';
			this.container.style.height = Math.max(minSize.height, (height + 2 * dy)) + 'px';
			mxEvent.consume(evt);
		}
	});
	
	var dropHandler = mxUtils.bind(this, function(evt)
	{
		if (startX != null && startY != null)
		{
			startX = null;
			startY = null;
			mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
			mxEvent.consume(evt);

			if (typeof this.onResize === 'function')
			{
				this.onResize(parseInt(this.container.style.width),
					parseInt(this.container.style.height));
			}
		}
	});

	mxEvent.addGestureListeners(resize, start, dragHandler, dropHandler);
	this.container.appendChild(resize);
};

/**
 * Removes the dialog from the DOM.
 */
Dialog.prototype.close = function(cancel, isEsc)
{
	if (this.onDialogClose != null)
	{
		if (this.onDialogClose(cancel, isEsc) == false)
		{
			return false;
		}
		
		this.onDialogClose = null;
	}
	
	if (this.dialogImg != null && this.dialogImg.parentNode != null)
	{
		this.dialogImg.parentNode.removeChild(this.dialogImg);
		this.dialogImg = null;
	}
	
	if (this.bg != null && this.bg.parentNode != null)
	{
		this.bg.parentNode.removeChild(this.bg);
	}

	if (this.editorUi.embedViewport != null)
	{
		this.editorUi.removeListener(this.resizeListener);
	}
	else
	{
		mxEvent.removeListener(window, 'resize', this.resizeListener);
	}

	if (this.container.parentNode != null)
	{
		this.container.parentNode.removeChild(this.container);
	}
};

/**
 * 
 */
var ErrorDialog = function(editorUi, title, message, buttonText, fn, retry, buttonText2, fn2, hide, buttonText3, fn3)
{
	hide = (hide != null) ? hide : true;
	
	var div = document.createElement('div');
	div.style.textAlign = 'center';
	div.style.flexDirection = 'column';
	div.style.maxHeight = '100%';
	div.style.display = 'flex';

	if (title != null)
	{
		var hd = document.createElement('div');
		hd.style.padding = '0px';
		hd.style.margin = '0px';
		hd.style.fontSize = '14px';
		hd.style.fontWeight = '600';
		hd.style.paddingBottom = '12px';
		hd.style.marginBottom = '10px';
		hd.style.borderBottom = '1px solid light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1))';
		hd.style.whiteSpace = 'nowrap';
		hd.style.textOverflow = 'ellipsis';
		hd.style.overflow = 'hidden';
		hd.style.flexShrink = '0';
		mxUtils.write(hd, title);
		hd.setAttribute('title', title);
		div.appendChild(hd);
	}

	var p2 = document.createElement('div');
	p2.style.lineHeight = '1.2em';
	p2.style.padding = '6px';
	p2.style.flexGrow = '1';
	p2.style.overflowY = 'auto';
	
	if (typeof message === 'string')
	{
		message = message.replace(/\n/g, '<br/>');
	}
	
	p2.innerHTML = Graph.sanitizeHtml(message);
	div.appendChild(p2);
	
	var btns = document.createElement('div');
	btns.style.marginTop = '12px';
	btns.style.textAlign = 'center';
	
	if (retry != null)
	{
		var retryBtn = mxUtils.button(mxResources.get('tryAgain'), function()
		{
			editorUi.hideDialog();
			retry();
		});
		
		retryBtn.className = 'geBtn';
		btns.appendChild(retryBtn);
		
		btns.style.textAlign = 'center';
	}
	
	if (buttonText3 != null)
	{
		var btn3 = mxUtils.button(buttonText3, function()
		{
			if (fn3 != null)
			{
				fn3();
			}
		});
		
		btn3.className = 'geBtn';
		btns.appendChild(btn3);
	}
	
	var btn = mxUtils.button(buttonText, function()
	{
		if (hide)
		{
			editorUi.hideDialog();
		}
		
		if (fn != null)
		{
			fn();
		}
	});
	
	btn.className = 'geBtn';
	btns.appendChild(btn);

	if (buttonText2 != null)
	{
		var mainBtn = mxUtils.button(buttonText2, function()
		{
			if (hide)
			{
				editorUi.hideDialog();
			}
			
			if (fn2 != null)
			{
				fn2();
			}
		});
		
		mainBtn.className = 'geBtn gePrimaryBtn';
		btns.appendChild(mainBtn);
	}

	this.init = function()
	{
		btn.focus();
	};
	
	div.appendChild(btns);

	this.container = div;
};

/**
 * Constructs a new print dialog.
 */
var PrintDialog = function(editorUi, title, fn, btnTitle)
{
	this.create(editorUi, title, fn, btnTitle);
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.prototype.create = function(editorUi)
{
	var graph = editorUi.editor.graph;
	var row, td;
	
	var table = document.createElement('table');
	table.style.width = '100%';
	table.style.height = '100%';
	var tbody = document.createElement('tbody');
	
	row = document.createElement('tr');
	
	var onePageCheckBox = document.createElement('input');
	onePageCheckBox.setAttribute('type', 'checkbox');
	td = document.createElement('td');
	td.setAttribute('colspan', '2');
	td.style.fontSize = '10pt';
	td.appendChild(onePageCheckBox);
	
	var span = document.createElement('span');
	mxUtils.write(span, ' ' + mxResources.get('fitPage'));
	td.appendChild(span);
	
	mxEvent.addListener(span, 'click', function(evt)
	{
		onePageCheckBox.checked = !onePageCheckBox.checked;
		pageCountCheckBox.checked = !onePageCheckBox.checked;
		mxEvent.consume(evt);
	});
	
	mxEvent.addListener(onePageCheckBox, 'change', function()
	{
		pageCountCheckBox.checked = !onePageCheckBox.checked;
	});
	
	row.appendChild(td);
	tbody.appendChild(row);

	row = row.cloneNode(false);
	
	var pageCountCheckBox = document.createElement('input');
	pageCountCheckBox.setAttribute('type', 'checkbox');
	td = document.createElement('td');
	td.style.fontSize = '10pt';
	td.appendChild(pageCountCheckBox);
	
	var span = document.createElement('span');
	mxUtils.write(span, ' ' + mxResources.get('posterPrint') + ':');
	td.appendChild(span);
	
	mxEvent.addListener(span, 'click', function(evt)
	{
		pageCountCheckBox.checked = !pageCountCheckBox.checked;
		onePageCheckBox.checked = !pageCountCheckBox.checked;
		mxEvent.consume(evt);
	});
	
	row.appendChild(td);
	
	var pageCountInput = document.createElement('input');
	pageCountInput.setAttribute('value', '1');
	pageCountInput.setAttribute('type', 'number');
	pageCountInput.setAttribute('min', '1');
	pageCountInput.setAttribute('size', '4');
	pageCountInput.setAttribute('disabled', 'disabled');
	pageCountInput.style.width = '50px';

	td = document.createElement('td');
	td.style.fontSize = '10pt';
	td.appendChild(pageCountInput);
	mxUtils.write(td, ' ' + mxResources.get('pages') + ' (max)');
	row.appendChild(td);
	tbody.appendChild(row);

	mxEvent.addListener(pageCountCheckBox, 'change', function()
	{
		if (pageCountCheckBox.checked)
		{
			pageCountInput.removeAttribute('disabled');
		}
		else
		{
			pageCountInput.setAttribute('disabled', 'disabled');
		}

		onePageCheckBox.checked = !pageCountCheckBox.checked;
	});

	row = row.cloneNode(false);
	
	td = document.createElement('td');
	mxUtils.write(td, mxResources.get('pageScale') + ':');
	row.appendChild(td);
	
	td = document.createElement('td');
	var pageScaleInput = document.createElement('input');
	pageScaleInput.setAttribute('value', '100 %');
	pageScaleInput.setAttribute('size', '5');
	pageScaleInput.style.width = '50px';
	
	td.appendChild(pageScaleInput);
	row.appendChild(td);
	tbody.appendChild(row);
	
	row = document.createElement('tr');
	td = document.createElement('td');
	td.colSpan = 2;
	td.style.paddingTop = '30px';
	td.setAttribute('align', 'right');
	
	// Overall scale for print-out to account for print borders in dialogs etc
	function preview(print)
	{
		var autoOrigin = onePageCheckBox.checked || pageCountCheckBox.checked;
		var printScale = parseInt(pageScaleInput.value) / 100;
		
		if (isNaN(printScale))
		{
			printScale = 1;
			pageScaleInput.value = '100%';
		}

		// Workaround to match available paper size in actual print output
		if (mxClient.IS_SF)
		{
			printScale *= 0.75;
		}
		
		var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
		var scale = 1 / graph.pageScale;
		
		if (autoOrigin)
		{
    		var pageCount = (onePageCheckBox.checked) ? 1 : parseInt(pageCountInput.value);
			
			if (!isNaN(pageCount))
			{
				scale = mxUtils.getScaleForPageCount(pageCount, graph, pf);
			}
		}

		// Negative coordinates are cropped or shifted if page visible
		var border = 0;
		var x0 = 0;
		var y0 = 0;

		// Applies print scale
		pf = mxRectangle.fromRectangle(pf);
		pf.width = Math.ceil(pf.width * printScale);
		pf.height = Math.ceil(pf.height * printScale);
		scale *= printScale;
		
		// Starts at first visible page
		if (!autoOrigin && graph.pageVisible)
		{
			var layout = graph.getPageLayout();
			x0 -= layout.x * pf.width;
			y0 -= layout.y * pf.height;
		}
		else
		{
			autoOrigin = true;
		}
		
		var preview = PrintDialog.createPrintPreview(graph, scale, pf, border, x0, y0, autoOrigin);
		preview.open();
	
		if (print)
		{
			PrintDialog.printPreview(preview);
		}
	};
	
	var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
	{
		editorUi.hideDialog();
	});
	cancelBtn.className = 'geBtn';
	
	if (editorUi.editor.cancelFirst)
	{
		td.appendChild(cancelBtn);
	}

	if (PrintDialog.previewEnabled)
	{
		var previewBtn = mxUtils.button(mxResources.get('preview'), function()
		{
			editorUi.hideDialog();
			preview(false);
		});
		previewBtn.className = 'geBtn';
		td.appendChild(previewBtn);
	}
	
	var printBtn = mxUtils.button(mxResources.get((!PrintDialog.previewEnabled) ? 'ok' : 'print'), function()
	{
		editorUi.hideDialog();
		preview(true);
	});
	printBtn.className = 'geBtn gePrimaryBtn';
	td.appendChild(printBtn);
	
	if (!editorUi.editor.cancelFirst)
	{
		td.appendChild(cancelBtn);
	}

	row.appendChild(td);
	tbody.appendChild(row);
	
	table.appendChild(tbody);

	var div = document.createElement('div');
	div.style.paddingBottom = '20px';
	div.appendChild(table);
	this.container = div;
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.printPreview = function(preview)
{
	try
	{
		if (preview.wnd != null)
		{
			var printFn = function()
			{
				preview.wnd.focus();
				preview.wnd.print();
				preview.wnd.close();
			};
			
			// Workaround for rendering SVG output and
			// make window available for printing
			window.setTimeout(printFn, 500);
		}
	}
	catch (e)
	{
		// ignores possible Access Denied
	}
};

/**
 * Constructs a new print dialog.
 */
PrintDialog.createPrintPreview = function(graph, scale, pf, border, x0, y0, autoOrigin)
{
	var preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
	preview.title = mxResources.get('preview');
	preview.addPageCss = !mxClient.IS_SF;
	preview.printBackgroundImage = true;
	preview.autoOrigin = autoOrigin;
	var bg = graph.background;
	
	if (bg == null || bg == '' || bg == mxConstants.NONE)
	{
		bg = '#ffffff';
	}
	
	preview.backgroundColor = bg;

	// Excludes hints from being printed as text labels
	var isTextLabel = preview.isTextLabel;

	preview.isTextLabel = function(node)
	{
		return !node.className == 'geHint' && isTextLabel.apply(this, arguments);
	};

	// Makes relative links absolute
	var getLinkForCellState = preview.getLinkForCellState;

	preview.getLinkForCellState = function(state)
	{
		return graph.getAbsoluteUrl(getLinkForCellState.apply(this, arguments));
	};

	return preview;
};

/**
 * Specifies if the preview button should be enabled. Default is true.
 */
PrintDialog.previewEnabled = true;

/**
 * Constructs a new page setup dialog.
 */
var PageSetupDialog = function(editorUi)
{
	var graph = editorUi.editor.graph;
	var div = document.createElement('div');

	// Consistent label width and content spacing across rows so inputs
	// align even with longer translations (e.g. German "Gitternetzgröße").
	var labelMinWidth = '140px';
	var contentMargin = '8px';

	var styleLabel = function(lbl)
	{
		lbl.style.minWidth = labelMinWidth;
		return lbl;
	};

	var styleContent = function(elt)
	{
		elt.style.marginLeft = contentMargin;
		return elt;
	};

	var hd = document.createElement('h3');
	mxUtils.write(hd, mxResources.get('pageSetup'));
	hd.style.cssText = 'width:100%;text-align:center;margin-top:0px;margin-bottom:10px';
	div.appendChild(hd);

	// Paper size section
	var paperSection = document.createElement('div');
	paperSection.className = 'geDialogSection';

	var paperRow = document.createElement('div');
	paperRow.className = 'geDialogFormRow';

	var paperLabel = document.createElement('span');
	paperLabel.className = 'geDialogFormLabel';
	mxUtils.write(paperLabel, mxResources.get('paperSize') + ':');
	paperRow.appendChild(styleLabel(paperLabel));

	var paperContent = document.createElement('div');
	paperContent.style.flex = '1';
	paperContent.style.minWidth = '0';

	var accessor = PageSetupDialog.addPageFormatPanel(paperContent,
		'pagesetupdialog', graph.pageFormat);

	paperRow.appendChild(styleContent(paperContent));
	paperSection.appendChild(paperRow);
	div.appendChild(paperSection);

	// Grid size section
	var gridSection = document.createElement('div');
	gridSection.className = 'geDialogSection';

	var gridRow = document.createElement('div');
	gridRow.className = 'geDialogFormRow';

	var gridLabel = document.createElement('span');
	gridLabel.className = 'geDialogFormLabel';
	mxUtils.write(gridLabel, mxResources.get('gridSize') + ':');
	gridRow.appendChild(styleLabel(gridLabel));

	var gridSizeInput = document.createElement('input');
	gridSizeInput.setAttribute('type', 'number');
	gridSizeInput.setAttribute('min', '0');
	gridSizeInput.style.width = '60px';
	gridSizeInput.style.flex = '0 0 auto';
	gridSizeInput.value = graph.getGridSize();
	gridRow.appendChild(styleContent(gridSizeInput));

	mxEvent.addListener(gridSizeInput, 'change', function()
	{
		var value = parseInt(gridSizeInput.value);
		gridSizeInput.value = Math.max(1, (isNaN(value)) ? graph.getGridSize() : value);
	});

	gridSection.appendChild(gridRow);
	div.appendChild(gridSection);

	// Background section
	var bgSection = document.createElement('div');
	bgSection.className = 'geDialogSection';

	var bgRow = document.createElement('div');
	bgRow.className = 'geDialogFormRow';

	var bgLabel = document.createElement('span');
	bgLabel.className = 'geDialogFormLabel';
	mxUtils.write(bgLabel, mxResources.get('background') + ':');
	bgRow.appendChild(styleLabel(bgLabel));

	var bgContent = document.createElement('div');
	bgContent.style.display = 'flex';
	bgContent.style.alignItems = 'center';
	bgContent.style.gap = '8px';
	bgContent.style.flex = '1';
	bgContent.style.minWidth = '0';
	styleContent(bgContent);

	var imgPreview = document.createElement('div');
	imgPreview.style.display = 'inline-block';
	imgPreview.style.verticalAlign = 'middle';
	imgPreview.style.backgroundPosition = 'center center';
	imgPreview.style.backgroundRepeat = 'no-repeat';
	imgPreview.style.backgroundSize = 'contain';
	imgPreview.style.border = '1px solid lightGray';
	imgPreview.style.borderRadius = '4px';
	imgPreview.style.height = '32px';
	imgPreview.style.width = '64px';
	imgPreview.style.cursor = 'pointer';
	imgPreview.style.padding = '4px';
	imgPreview.style.flexShrink = '0';

	var newBackgroundImage = graph.backgroundImage;
	var newBackgroundColor = graph.background;
	var newShadowVisible = graph.shadowVisible;

	function updateBackgroundImage()
	{
		var img = newBackgroundImage;

		if (img != null && img.originalSrc != null)
		{
			img = editorUi.createImageForPageLink(img.originalSrc, null);
		}

		if (img != null && img.src != null)
		{
			imgPreview.style.backgroundImage = 'url(' + img.src + ')';
			imgPreview.style.display = 'inline-block';
		}
		else
		{
			imgPreview.style.backgroundImage = '';
			imgPreview.style.display = 'none';
		}

		imgPreview.style.backgroundColor = '';

		if (newBackgroundColor != null && newBackgroundColor != mxConstants.NONE)
		{
			imgPreview.style.backgroundColor = newBackgroundColor;
			imgPreview.style.display = 'inline-block';
		}
	};

	var changeImage = function(evt)
	{
		editorUi.showBackgroundImageDialog(function(image, failed, color, shadowVisible)
		{
			if (!failed)
			{
				if (image != null && image.src != null && Graph.isPageLink(image.src))
				{
					image = {originalSrc: image.src};
				}

				newBackgroundImage = image;
				newShadowVisible = shadowVisible;
			}

			newBackgroundColor = color;
			updateBackgroundImage();
		}, newBackgroundImage, newBackgroundColor, true);

		mxEvent.consume(evt);
	};

	mxEvent.addListener(imgPreview, 'click', changeImage);

	var changeImageLink = document.createElement('button');
	changeImageLink.className = 'geBtn';
	changeImageLink.style.margin = '0px';
	mxUtils.write(changeImageLink, mxResources.get('change') + '...');
	mxEvent.addListener(changeImageLink, 'click', changeImage);

	updateBackgroundImage();
	bgContent.appendChild(imgPreview);
	bgContent.appendChild(changeImageLink);
	bgRow.appendChild(bgContent);

	bgSection.appendChild(bgRow);
	div.appendChild(bgSection);

	// Adaptive colors section
	var adaptiveSection = document.createElement('div');
	adaptiveSection.className = 'geDialogSection';

	var adaptiveRow = document.createElement('div');
	adaptiveRow.className = 'geDialogFormRow';

	var adaptiveLabel = document.createElement('span');
	adaptiveLabel.className = 'geDialogFormLabel';
	mxUtils.write(adaptiveLabel, mxResources.get('adaptiveColors') + ':');
	adaptiveRow.appendChild(styleLabel(adaptiveLabel));

	var adaptiveDropdown = document.createElement('select');
	styleContent(adaptiveDropdown);

	var addAdaptiveOption = function(value, label)
	{
		var opt = document.createElement('option');
		opt.setAttribute('value', value);
		mxUtils.write(opt, label);
		adaptiveDropdown.appendChild(opt);
	};

	addAdaptiveOption('default', mxResources.get('default') + ' (' +
		mxResources.get(Graph.getDefaultAdaptiveColorsKey()) + ')');
	addAdaptiveOption('auto', mxResources.get('automatic'));
	addAdaptiveOption('simple', mxResources.get('simple'));
	addAdaptiveOption('none', mxResources.get('none'));

	adaptiveDropdown.value = (graph.adaptiveColors == null) ?
		'default' : graph.adaptiveColors;

	adaptiveRow.appendChild(adaptiveDropdown);

	if (editorUi.menus != null && editorUi.menus.createHelpLink != null &&
		(!editorUi.isOffline() || mxClient.IS_CHROMEAPP || EditorUi.isElectronApp))
	{
		var helpLink = editorUi.menus.createHelpLink(
			'https://github.com/jgraph/drawio/discussions/4713');
		helpLink.style.marginLeft = '8px';
		adaptiveRow.appendChild(helpLink);
	}

	adaptiveSection.appendChild(adaptiveRow);
	div.appendChild(adaptiveSection);

	// Apply function
	var applyFn = function()
	{
		var gridSize = parseInt(gridSizeInput.value);

		if (!isNaN(gridSize) && graph.gridSize !== gridSize)
		{
			graph.setGridSize(gridSize);
		}

		var change = new ChangePageSetup(editorUi, newBackgroundColor,
			newBackgroundImage, accessor.get());
		change.ignoreColor = graph.background == newBackgroundColor;

		var oldSrc = (graph.backgroundImage != null) ? graph.backgroundImage.src : null;
		var newSrc = (newBackgroundImage != null) ? newBackgroundImage.src : null;

		change.ignoreImage = oldSrc === newSrc;

		if (newShadowVisible != null)
		{
			change.shadowVisible = newShadowVisible;
		}

		var newAdaptive = adaptiveDropdown.value;
		var currentAdaptive = (graph.adaptiveColors == null) ?
			'default' : graph.adaptiveColors;
		var adaptiveChanged = newAdaptive != currentAdaptive;

		if (adaptiveChanged)
		{
			change.adaptiveColors = newAdaptive;
		}

		if (graph.pageFormat.width != change.previousFormat.width ||
			graph.pageFormat.height != change.previousFormat.height ||
			!change.ignoreColor || !change.ignoreImage ||
			change.shadowVisible != graph.shadowVisible ||
			adaptiveChanged)
		{
			graph.model.execute(change);
		}
	};

	var dlg = new CustomDialog(editorUi, div, applyFn, null,
		mxResources.get('apply'));
	this.container = dlg.container;
};

/**
 * 
 */
PageSetupDialog.addPageFormatPanel = function(div, namePostfix, pageFormat, pageFormatListener)
{
	var formatName = 'format-' + namePostfix;
	
	var portraitCheckBox = document.createElement('input');
	portraitCheckBox.setAttribute('name', formatName);
	portraitCheckBox.setAttribute('type', 'radio');
	portraitCheckBox.setAttribute('value', 'portrait');
	
	var landscapeCheckBox = document.createElement('input');
	landscapeCheckBox.setAttribute('name', formatName);
	landscapeCheckBox.setAttribute('type', 'radio');
	landscapeCheckBox.setAttribute('value', 'landscape');
	
	var paperSizeSelect = document.createElement('select');
	paperSizeSelect.style.position = 'relative';
	paperSizeSelect.style.marginBottom = '4px';
	paperSizeSelect.style.borderRadius = '4px';
	paperSizeSelect.style.borderWidth = '1px';
	paperSizeSelect.style.borderStyle = 'solid';
	paperSizeSelect.style.boxSizing = 'border-box';
	paperSizeSelect.style.padding = '2px';
	paperSizeSelect.style.width = '210px';

	var formatDiv = document.createElement('div');
	formatDiv.style.alignItems = 'center';
	formatDiv.style.whiteSpace = 'nowrap';
	formatDiv.style.marginLeft = '4px';
	formatDiv.style.width = '210px';
	formatDiv.style.height = '24px';

	portraitCheckBox.style.margin = '0 6px 0 0';
	formatDiv.appendChild(portraitCheckBox);
	
	var portraitSpan = document.createElement('span');
	portraitSpan.style.maxWidth = '100px';
	mxUtils.write(portraitSpan, mxResources.get('portrait'));
	formatDiv.appendChild(portraitSpan);

	landscapeCheckBox.style.margin = '0 6px 0 10px';
	formatDiv.appendChild(landscapeCheckBox);
	
	var landscapeSpan = document.createElement('span');
	landscapeSpan.style.width = '100px';
	mxUtils.write(landscapeSpan, mxResources.get('landscape'));
	formatDiv.appendChild(landscapeSpan)

	var customDiv = document.createElement('div');
	customDiv.style.whiteSpace = 'nowrap';
	customDiv.style.fontSize = '12px';
	customDiv.style.width = '210px';
	customDiv.style.height = '24px';

	var widthInput = document.createElement('input');
	widthInput.setAttribute('size', '6');
	widthInput.setAttribute('title', mxResources.get('width'));
	widthInput.style.textAlign = 'right';
	customDiv.appendChild(widthInput);
	mxUtils.write(customDiv, ' x ');

	var heightInput = document.createElement('input');
	heightInput.setAttribute('size', '6');
	heightInput.setAttribute('title', mxResources.get('height'));
	heightInput.style.textAlign = 'right';
	customDiv.appendChild(heightInput);

	var unitSelect = document.createElement('select');
	unitSelect.style.marginLeft = '4px';
	unitSelect.style.boxSizing = 'border-box';
	var units = [{label: mxResources.get('points'), unit: mxConstants.POINTS},
		{label: mxResources.get('inches'), unit: mxConstants.INCHES},
		{label: mxResources.get('millimeters'), unit: mxConstants.MILLIMETERS}];

	for (var i = 0; i < units.length; i++)
	{
		var unitOption = document.createElement('option');
		unitOption.setAttribute('value', units[i].unit);
		mxUtils.write(unitOption, units[i].label);
		unitSelect.appendChild(unitOption);
	}

	unitSelect.value = Editor.pageSizeUnit;
	customDiv.appendChild(unitSelect);

	formatDiv.style.display = 'none';
	customDiv.style.display = 'none';
	
	var pf = new Object();
	var formats = PageSetupDialog.getFormats();
	
	for (var i = 0; i < formats.length; i++)
	{
		var f = formats[i];
		pf[f.key] = f;

		var paperSizeOption = document.createElement('option');
		paperSizeOption.setAttribute('value', f.key);
		mxUtils.write(paperSizeOption, f.title);
		paperSizeSelect.appendChild(paperSizeOption);
	}
	
	var listener = function()
	{
		paperSizeSelect.value = 'custom';

		for (var i = 0; i < formats.length; i++)
		{
			var f = formats[i];

			if (f.format != null)
			{
				// Fixes wrong values for previous A4 and A5 page sizes
				if (f.key == 'a4')
				{
					if (pageFormat.width == 826)
					{
						pageFormat = mxRectangle.fromRectangle(pageFormat);
						pageFormat.width = 827;
					}
					else if (pageFormat.height == 826)
					{
						pageFormat = mxRectangle.fromRectangle(pageFormat);
						pageFormat.height = 827;
					}
				}
				else if (f.key == 'a5')
				{
					if (pageFormat.width == 584)
					{
						pageFormat = mxRectangle.fromRectangle(pageFormat);
						pageFormat.width = 583;
					}
					else if (pageFormat.height == 584)
					{
						pageFormat = mxRectangle.fromRectangle(pageFormat);
						pageFormat.height = 583;
					}
				}
				
				if (pageFormat.width == f.format.width && pageFormat.height == f.format.height)
				{
					paperSizeSelect.value = f.key;
					portraitCheckBox.setAttribute('checked', 'checked');
					portraitCheckBox.defaultChecked = true;
					portraitCheckBox.checked = true;
					landscapeCheckBox.removeAttribute('checked');
					landscapeCheckBox.defaultChecked = false;
					landscapeCheckBox.checked = false;
					detected = true;
				}
				else if (pageFormat.width == f.format.height && pageFormat.height == f.format.width)
				{
					paperSizeSelect.value = f.key;
					portraitCheckBox.removeAttribute('checked');
					portraitCheckBox.defaultChecked = false;
					portraitCheckBox.checked = false;
					landscapeCheckBox.setAttribute('checked', 'checked');
					landscapeCheckBox.defaultChecked = true;
					landscapeCheckBox.checked = true;
					detected = true;
				}
			}
		}
		
		// Selects custom format which is last in list
		if (paperSizeSelect.value == 'custom')
		{
			widthInput.value = Editor.toUnit(pageFormat.width, unitSelect.value);
			heightInput.value = Editor.toUnit(pageFormat.height, unitSelect.value);
			portraitCheckBox.setAttribute('checked', 'checked');
			paperSizeSelect.value = 'custom';
			formatDiv.style.display = 'none';
			customDiv.style.display = '';
		}
		else
		{
			formatDiv.style.display = 'flex';
			customDiv.style.display = 'none';
		}
	};

	listener();

	div.appendChild(paperSizeSelect);
	mxUtils.br(div);
	div.appendChild(formatDiv);
	div.appendChild(customDiv);
	
	var update = function(evt, quiet)
	{
		var f = pf[paperSizeSelect.value];

		if (f.format != null)
		{
			widthInput.value = Editor.toUnit((!landscapeCheckBox.checked) ?
				f.format.width : f.format.height, unitSelect.value);
			heightInput.value = Editor.toUnit((!landscapeCheckBox.checked) ?
				f.format.height : f.format.width, unitSelect.value);

			customDiv.style.display = 'none';
			formatDiv.style.display = 'flex';
		}
		else
		{
			formatDiv.style.display = 'none';
			customDiv.style.display = '';
		}
		
		var wi = parseFloat(widthInput.value);
		
		if (isNaN(wi) || wi <= 0)
		{
			widthInput.value = Editor.toUnit(pageFormat.width, unitSelect.value);
		}
		
		var hi = parseFloat(heightInput.value);
		
		if (isNaN(hi) || hi <= 0)
		{
			heightInput.value = Editor.toUnit(pageFormat.height, unitSelect.value);
		}
		
		var newPageFormat = new mxRectangle(0, 0,
			Math.floor(Editor.fromUnit(parseFloat(widthInput.value), unitSelect.value)),
			Math.floor(Editor.fromUnit(parseFloat(heightInput.value), unitSelect.value)));
		
		// Initial select of custom should not update page format to avoid update of combo
		if (!quiet && (newPageFormat.width != pageFormat.width ||
			newPageFormat.height != pageFormat.height))
		{
			pageFormat = newPageFormat;

			// Updates page format and reloads format panel
			if (pageFormatListener != null)
			{
				pageFormatListener(pageFormat);
			}
		}
	};

	mxEvent.addListener(portraitSpan, 'click', function(evt)
	{
		portraitCheckBox.checked = true;
		update(evt);
		mxEvent.consume(evt);
	});
	
	mxEvent.addListener(landscapeSpan, 'click', function(evt)
	{
		landscapeCheckBox.checked = true;
		update(evt);
		mxEvent.consume(evt);
	});
	
	mxEvent.addListener(widthInput, 'blur', update);
	mxEvent.addListener(widthInput, 'click', update);
	mxEvent.addListener(heightInput, 'blur', update);
	mxEvent.addListener(heightInput, 'click', update);
	mxEvent.addListener(landscapeCheckBox, 'change', update);
	mxEvent.addListener(portraitCheckBox, 'change', update);
	mxEvent.addListener(paperSizeSelect, 'change', function(evt)
	{
		update(evt, paperSizeSelect.value == 'custom');
		mxEvent.consume(evt);
	});
	mxEvent.addListener(unitSelect, 'change', function(evt)
	{
		widthInput.value = Editor.toUnit(Editor.fromUnit(widthInput.value, Editor.pageSizeUnit), unitSelect.value);
		heightInput.value = Editor.toUnit(Editor.fromUnit(heightInput.value, Editor.pageSizeUnit), unitSelect.value);
		Editor.pageSizeUnit = unitSelect.value;
		update(evt, true);
		mxEvent.consume(evt);
	});

	update(null, true);
	
	return {set: function(value)
	{
		pageFormat = value;
		listener(null, null, true);
	},get: function()
	{
		return pageFormat;
	}, widthInput: widthInput,
		heightInput: heightInput};
};

/**
 * 
 */
PageSetupDialog.getFormats = function()
{
	return [{key: 'letter', title: 'US-Letter (8,5" x 11")', format: mxConstants.PAGE_FORMAT_LETTER_PORTRAIT},
	        {key: 'legal', title: 'US-Legal (8,5" x 14")', format: new mxRectangle(0, 0, 850, 1400)},
	        {key: 'tabloid', title: 'US-Tabloid (11" x 17")', format: new mxRectangle(0, 0, 1100, 1700)},
	        {key: 'executive', title: 'US-Executive (7" x 10")', format: new mxRectangle(0, 0, 700, 1000)},
	        {key: 'a0', title: 'A0 (841 mm x 1189 mm)', format: new mxRectangle(0, 0, 3300, 4681)},
	        {key: 'a1', title: 'A1 (594 mm x 841 mm)', format: new mxRectangle(0, 0, 2339, 3300)},
	        {key: 'a2', title: 'A2 (420 mm x 594 mm)', format: new mxRectangle(0, 0, 1654, 2336)},
	        {key: 'a3', title: 'A3 (297 mm x 420 mm)', format: new mxRectangle(0, 0, 1169, 1654)},
	        {key: 'a4', title: 'A4 (210 mm x 297 mm)', format: mxConstants.PAGE_FORMAT_A4_PORTRAIT},
	        {key: 'a5', title: 'A5 (148 mm x 210 mm)', format: new mxRectangle(0, 0, 583, 827)},
	        {key: 'a6', title: 'A6 (105 mm x 148 mm)', format: new mxRectangle(0, 0, 413, 583)},
	        {key: 'a7', title: 'A7 (74 mm x 105 mm)', format: new mxRectangle(0, 0, 291, 413)},
	        {key: 'b4', title: 'B4 (250 mm x 353 mm)', format: new mxRectangle(0, 0, 980, 1390)},
	        {key: 'b5', title: 'B5 (176 mm x 250 mm)', format: new mxRectangle(0, 0, 690, 980)},
	        {key: '16-9', title: '16:9 (1600 x 900)', format: new mxRectangle(0, 0, 900, 1600)},
	        {key: '16-10', title: '16:10 (1920 x 1200)', format: new mxRectangle(0, 0, 1200, 1920)},
	        {key: '4-3', title: '4:3 (1600 x 1200)', format: new mxRectangle(0, 0, 1200, 1600)},
	        {key: 'custom', title: mxResources.get('custom'), format: null}];
};

/**
 * Constructs a new filename dialog.
 */
var FilenameDialog = function(editorUi, filename, buttonText, fn, label,
	validateFn, content, helpLink, closeOnBtn, cancelFn, hints)
{
	closeOnBtn = (closeOnBtn != null) ? closeOnBtn : true;

	var container = document.createElement('div');
	var table = document.createElement('div');
	table.style.width = '100%';
	table.style.display = 'grid';
	table.style.gap = '5px 8px';
	table.style.gridAutoColumns = 'auto 1fr';

	// Workaround for clipped focus rectangle in FF
	table.style.boxSizing = 'border-box';
	table.style.padding = '3px';

	var td = document.createElement('div');
	td.style.display = 'inline-flex';
	td.style.alignItems = 'center';
	td.style.justifyContent = 'flex-end';
	td.style.minWidth = '0';

	// Wrapper for text ellipsis
	var wrapper = document.createElement('div');
	wrapper.style.display = 'inline-block';
	wrapper.style.textOverflow = 'ellipsis';
	wrapper.style.whiteSpace = 'nowrap';
	wrapper.style.overflow = 'hidden';
	wrapper.style.fontSize = '10pt';

	// Workaround for vertical clipping
	wrapper.style.padding = '2px 0';

	wrapper.setAttribute('title', label || mxResources.get('filename'));
	mxUtils.write(wrapper, (label || mxResources.get('filename')) + ':');

	td.appendChild(wrapper);
	table.appendChild(td);
	
	var nameInput = document.createElement('input');
	nameInput.setAttribute('value', filename || '');
	nameInput.style.flexGrow = '1';
	
	var genericBtn = mxUtils.button(buttonText, function()
	{
		if (validateFn == null || validateFn(nameInput.value))
		{
			if (closeOnBtn)
			{
				editorUi.hideDialog();
			}
			
			fn(nameInput.value);
		}
	});
	genericBtn.className = 'geBtn gePrimaryBtn';
	
	this.init = function()
	{
		if (label == null && content != null)
		{
			return;
		}

		if (hints != null)
		{
			Editor.selectFilename(nameInput);
		}
		else
		{
			nameInput.focus();
			
			if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
			{
				nameInput.select();
			}
			else
			{
				document.execCommand('selectAll', false, null);
			}
		}
		
		// Installs drag and drop handler for links
		if (Graph.fileSupport)
		{
			// Setup the dnd listeners
			var dlg = table.parentNode;
			
			if (dlg != null)
			{
				var dropElt = null;
					
				mxEvent.addListener(dlg, 'dragleave', function(evt)
				{
					if (dropElt != null)
				    {
						dropElt.style.backgroundColor = '';
				    	dropElt = null;
				    }
				    
					evt.stopPropagation();
					evt.preventDefault();
				});
				
				mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
				{
					if (dropElt == null)
					{
						dropElt = nameInput;
						dropElt.style.backgroundColor = '#ebf2f9';
					}
					
					evt.stopPropagation();
					evt.preventDefault();
				}));
						
				mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
				{
				    if (dropElt != null)
				    {
						dropElt.style.backgroundColor = '';
				    	dropElt = null;
				    }
	
				    if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
				    {
				    	nameInput.value = decodeURIComponent(evt.dataTransfer.getData('text/uri-list'));
				    	genericBtn.click();
				    }
	
				    evt.stopPropagation();
				    evt.preventDefault();
				}));
			}
		}
	};

	td = document.createElement('div');
	td.style.display = 'inline-flex';
	td.style.alignItems = 'center';
	td.style.gap = '4px';
	td.style.whiteSpace = 'nowrap';
	td.appendChild(nameInput);
	table.appendChild(td);
	
	if (label != null || content == null)
	{
		if (hints != null && editorUi.editor.diagramFileTypes != null)
		{
			td = document.createElement('div');
			td.style.display = 'inline-flex';
			td.style.alignItems = 'center';
			td.style.textOverflow = 'ellipsis';
			td.style.justifyContent = 'flex-end';
			td.style.fontSize = '10pt';
			mxUtils.write(td, mxResources.get('type') + ':');
			table.appendChild(td);

			td = document.createElement('div');
			td.style.display = 'inline-flex';
			td.style.alignItems = 'center';
			td.style.whiteSpace = 'nowrap';
			table.appendChild(td);

			var typeSelect = FilenameDialog.createFileTypes(editorUi,
				nameInput, editorUi.editor.diagramFileTypes);
			typeSelect.style.width = '100%';

			td.appendChild(typeSelect);
		}
	}
	
	if (content != null)
	{
		table.appendChild(content);
	}
	
	row = document.createElement('div');
	row.style.gridColumn = '1 / span 2';
	row.style.paddingTop = (hints != null) ? '6px' : '14px';
	row.style.whiteSpace = 'nowrap';
	row.style.display = 'inline-flex';
	row.style.alignItems = 'center';
	row.style.justifyContent = 'flex-end';
	row.setAttribute('align', 'right');
	
	var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
	{
		editorUi.hideDialog();
		
		if (cancelFn != null)
		{
			cancelFn();
		}
	});
	cancelBtn.className = 'geBtn';
	
	if (helpLink != null && !editorUi.isOffline())
	{
		row.appendChild(editorUi.createHelpIcon(helpLink));
	}

	if (editorUi.editor.cancelFirst)
	{
		row.appendChild(cancelBtn);
	}
	
	mxEvent.addListener(nameInput, 'keypress', function(e)
	{
		if (e.keyCode == 13)
		{
			genericBtn.click();
		}
	});
	
	row.appendChild(genericBtn);
	
	if (!editorUi.editor.cancelFirst)
	{
		row.appendChild(cancelBtn);
	}
	
	table.appendChild(row);
	container.appendChild(table);
	
	this.container = container;
};

/**
 * 
 */
FilenameDialog.filenameHelpLink = null;

/**
 * 
 */
FilenameDialog.createFileTypes = function(editorUi, nameInput, types)
{
	var typeSelect = document.createElement('select');

	for (var i = 0; i < types.length; i++)
	{
		var typeOption = document.createElement('option');
		typeOption.setAttribute('value', i);
		mxUtils.write(typeOption, mxResources.get(types[i].description) +
			' (.' + types[i].extension + ')');
		typeSelect.appendChild(typeOption);
	}
			
	mxEvent.addListener(typeSelect, 'change', function(evt)
	{
		var ext = types[typeSelect.value].extension;
		var idx2 = nameInput.value.lastIndexOf('.drawio.');
		var idx = (idx2 > 0) ? idx2 : nameInput.value.lastIndexOf('.');

		if (ext != 'drawio')
		{
			ext = 'drawio.' + ext;
		}
		
		if (idx > 0)
		{
			nameInput.value = nameInput.value.substring(0, idx + 1) + ext;
		}
		else
		{
			nameInput.value = nameInput.value + '.' + ext;
		}
		
		if ('createEvent' in document)
		{
		    var changeEvent = document.createEvent('HTMLEvents');
		    changeEvent.initEvent('change', false, true);
		    nameInput.dispatchEvent(changeEvent);
		}
		else
		{
		    nameInput.fireEvent('onchange');
		}
	});
	
	var nameInputChanged = function(evt)
	{
		var name = nameInput.value.toLowerCase();
		var active = 0;
		
		// Finds current extension
		for (var i = 0; i < types.length; i++)
		{
			var ext = types[i].extension;
			var subExt = null;

			if (ext != 'drawio')
			{
				subExt = ext;
				ext = '.drawio.' + ext;
			}

			if (name.substring(name.length - ext.length - 1) == '.' + ext ||
				(subExt != null && name.substring(name.length - subExt.length - 1) == '.' + subExt))
			{
				active = i;
				break;
			}
		}
		
		typeSelect.value = active;
	};
	
	mxEvent.addListener(nameInput, 'change', nameInputChanged);
	mxEvent.addListener(nameInput, 'keyup', nameInputChanged);
	nameInputChanged();

	// Applies default file type from configuration
	if (Editor.defaultFileType != null && typeSelect.value == '0')
	{
		for (var i = 0; i < types.length; i++)
		{
			if (types[i].extension == Editor.defaultFileType)
			{
				typeSelect.value = i;

				var ext = types[i].extension;
				var idx2 = nameInput.value.lastIndexOf('.drawio.');
				var idx = (idx2 > 0) ? idx2 : nameInput.value.lastIndexOf('.');

				if (ext != 'drawio')
				{
					ext = 'drawio.' + ext;
				}

				if (idx > 0)
				{
					nameInput.value = nameInput.value.substring(0, idx + 1) + ext;
				}
				else
				{
					nameInput.value = nameInput.value + '.' + ext;
				}

				break;
			}
		}
	}

	return typeSelect;
};

/**
 * 
 */
var WrapperWindow = function(editorUi, title, x, y, w, h, fn, div)
{
	div = (div != null) ? div : document.createElement('div');

	this.window = new mxWindow(title, div, x, y, w, h, true, true);
	this.window.destroyOnClose = false;
	this.window.setMaximizable(false);
	this.window.setResizable(true);
	this.window.setClosable(true);
	this.window.setVisible(true);

	editorUi.installResizeHandler(this, true);
	fn(div);
};

/**
 * Static overrides
 */
(function()
{
	// Uses HTML for background pages (to support grid background image)
	mxGraphView.prototype.validateBackgroundPage = function()
	{
		var graph = this.graph;
		
		if (graph.container != null && !graph.transparentBackground)
		{
			if (graph.pageVisible)
			{
				var bounds = this.getBackgroundPageBounds();
				
				if (this.backgroundPageShape == null)
				{
					// Finds first element in graph container
					var firstChild = graph.container.firstChild;
					
					while (firstChild != null && firstChild.nodeType != mxConstants.NODETYPE_ELEMENT)
					{
						firstChild = firstChild.nextSibling;
					}
					
					if (firstChild != null)
					{
						this.backgroundPageShape = this.createBackgroundPageShape(bounds);
						this.backgroundPageShape.scale = 1;
						
						// IE8 standards has known rendering issues inside mxWindow but not using shadow is worse.
						this.backgroundPageShape.isShadow = true;
						this.backgroundPageShape.dialect = mxConstants.DIALECT_STRICTHTML;
						this.backgroundPageShape.init(graph.container);
	
						// Required for the browser to render the background page in correct order
						firstChild.style.position = 'absolute';
						graph.container.insertBefore(this.backgroundPageShape.node, firstChild);
						this.backgroundPageShape.redraw();
						
						this.backgroundPageShape.node.className = 'geBackgroundPage';
						
						// Adds listener for double click handling on background
						mxEvent.addListener(this.backgroundPageShape.node, 'dblclick',
							mxUtils.bind(this, function(evt)
							{
								graph.dblClick(evt);
							})
						);
						
						// Adds basic listeners for graph event dispatching outside of the
						// container and finishing the handling of a single gesture
						mxEvent.addGestureListeners(this.backgroundPageShape.node,
							mxUtils.bind(this, function(evt)
							{
								graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
							}),
							mxUtils.bind(this, function(evt)
							{
								// Hides the tooltip if mouse is outside container
								if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover())
								{
									graph.tooltipHandler.hide();
								}
								
								if (graph.isMouseDown && !mxEvent.isConsumed(evt))
								{
									graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
								}
							}),
							mxUtils.bind(this, function(evt)
							{
								graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
							})
						);
					}
				}
				else
				{
					this.backgroundPageShape.scale = 1;
					this.backgroundPageShape.bounds = bounds;
					this.backgroundPageShape.redraw();
				}
			}
			else if (this.backgroundPageShape != null)
			{
				this.backgroundPageShape.destroy();
				this.backgroundPageShape = null;
			}
			
			this.validateBackgroundStyles();
		}
	};

	// Updates the CSS of the background to draw the grid and background color
	mxGraphView.prototype.validateBackgroundStyles = function(factor, cx, cy)
	{
		var graph = this.graph;
		factor = (factor != null) ? factor : 1;
		var color = mxUtils.getLightDarkColor((graph.background == null ||
			graph.background == mxConstants.NONE) ?
			graph.defaultPageBackgroundColor : graph.background).cssText;
		var pageBorder = mxUtils.getLightDarkColor(
			graph.defaultPageBorderColor).cssText;
		var gridColor = (color != null &&
			this.gridColor != color.toLowerCase()) ?
			this.gridColor : '#ffffff';
		var image = 'none';
		var position = '';

		// Uses light custom background with simple adaptive colors
		if (graph.getAdaptiveColors() == 'simple' &&
			graph.background != mxConstants.NONE &&
			graph.background != null)
		{
			color = graph.background;
		}
		
		if (graph.isGridEnabled() || graph.gridVisible)
		{
			var phase = 10;
			
			if (mxClient.IS_SVG)
			{
				// Paints the grid
				image = unescape(encodeURIComponent(this.createSvgGrid(gridColor, factor)));
				image = (window.btoa) ? btoa(image) : Base64.encode(image, true);
				image = 'url(' + 'data:image/svg+xml;base64,' + image + ')'
				phase = graph.gridSize * this.scale * this.gridSteps * factor;
			}
			else
			{
				// Fallback to grid wallpaper with fixed size
				image = 'url(' + this.gridImage + ')';
			}
			
			var x0 = 0;
			var y0 = 0;

			var dx = (cx != null) ? cx - this.translate.x * this.scale : 0;
			var dy = (cy != null) ? cy - this.translate.y * this.scale : 0;

			var p = graph.gridSize * this.scale * this.gridSteps;
			var ddx = dx % p;
			var ddy = dy % p;
			
			if (graph.view.backgroundPageShape != null)
			{
				var bds = this.getBackgroundPageBounds();
				
				x0 = 1 + bds.x;
				y0 = 1 + bds.y;
			}
			
			// Computes the offset to maintain origin for grid
			position = -Math.round(phase - mxUtils.mod(this.translate.x * this.scale - x0 + dx, phase) + ddx * factor) + 'px ' +
				-Math.round(phase - mxUtils.mod(this.translate.y * this.scale - y0 + dy, phase) + ddy * factor) + 'px';
		}
		
		var canvas = graph.view.canvas;
		
		if (canvas.ownerSVGElement != null)
		{
			canvas = canvas.ownerSVGElement;
		}

		var useDiagramBackground = !Editor.isDarkMode() && graph.enableDiagramBackground;
		
		if (graph.view.backgroundPageShape != null)
		{
			graph.view.backgroundPageShape.node.style.backgroundPosition = position;
			graph.view.backgroundPageShape.node.style.backgroundImage = image;
			graph.view.backgroundPageShape.node.style.backgroundColor = color;
			graph.view.backgroundPageShape.node.style.borderColor = pageBorder;
			graph.view.backgroundPageShape.node.style.colorScheme =
				(graph.getAdaptiveColors() == 'none') ? 'light' : '';
			canvas.style.backgroundImage = 'none';
			canvas.style.backgroundColor = '';

			if (useDiagramBackground)
			{
				graph.container.style.backgroundColor = graph.diagramBackgroundColor;
			}
			else
			{
				graph.container.style.backgroundColor = '';
			}
		}
		else
		{
			canvas.style.backgroundPosition = position;
			canvas.style.backgroundImage = image;

			if (urlParams['transparent'] == '1')
			{
				graph.container.style.background = 'transparent';
			}
			else if (useDiagramBackground && (graph.background == null ||
				graph.background == mxConstants.NONE))
			{
				canvas.style.backgroundColor = graph.diagramBackgroundColor;
				graph.container.style.backgroundColor = '';
			}
			else
			{
				canvas.style.backgroundColor = color;
			}
		}
	};
	
	// Returns the SVG required for painting the background grid.
	mxGraphView.prototype.createSvgGrid = function(color, factor)
	{
		factor = (factor != null) ? factor : 1;
		var tmp = this.graph.gridSize * this.scale * factor;
		
		while (tmp < this.minGridSize)
		{
			tmp *= 2;
		}
		
		var tmp2 = this.gridSteps * tmp;
		
		// Small grid lines
		var d = [];
		
		for (var i = 1; i < this.gridSteps; i++)
		{
			var tmp3 = i * tmp;
			d.push('M 0 ' + tmp3 + ' L ' + tmp2 + ' ' + tmp3 + ' M ' + tmp3 + ' 0 L ' + tmp3 + ' ' + tmp2);
		}
		
		// KNOWN: Rounding errors for certain scales (eg. 144%, 121% in Chrome, FF and Safari). Workaround
		// in Chrome is to use 100% for the svg size, but this results in blurred grid for large diagrams.
		var size = tmp2;
		var cssColor = mxUtils.getLightDarkColor(color);
		var scheme = 'color-scheme: light dark;';

		// Workaround for ignored parent scheme in Safari
		if (mxClient.IS_SF)
		{
			scheme =  'color-scheme: ' +
				(this.graph.getAdaptiveColors() != 'none' &&
				Editor.isDarkMode() ? 'dark' : 'light');
		}
		
		var svg = '<svg style="' + scheme + '" width="' + size + '" height="' + size + '" xmlns="' + mxConstants.NS_SVG + '">' +
		    '<defs><pattern id="grid" width="' + tmp2 + '" height="' + tmp2 + '" patternUnits="userSpaceOnUse">' +
		    '<path d="' + d.join(' ') + '" fill="none" style="stroke:' + mxUtils.htmlEntities(cssColor.cssText) +
			';" stroke="' + cssColor.light + '" opacity="0.2" stroke-width="1"/>' +
		    '<path d="M ' + tmp2 + ' 0 L 0 0 0 ' + tmp2 + '" fill="none" style="stroke:' +
			mxUtils.htmlEntities(cssColor.cssText) + ';" stroke="' +
			cssColor.light + '" stroke-width="1"/>' +
		    '</pattern></defs><rect width="100%" height="100%" fill="url(#grid)"/></svg>';

		return svg;
	};

	// Adds panning for the grid with no page view and disabled scrollbars
	var mxGraphPanGraph = mxGraph.prototype.panGraph;
	mxGraph.prototype.panGraph = function(dx, dy)
	{
		mxGraphPanGraph.apply(this, arguments);
		
		if (this.shiftPreview1 != null)
		{
			var canvas = this.view.canvas;
			
			if (canvas.ownerSVGElement != null)
			{
				canvas = canvas.ownerSVGElement;
			}
			
			var phase = this.gridSize * this.view.scale * this.view.gridSteps;
			var position = -Math.round(phase - mxUtils.mod(this.view.translate.x * this.view.scale + dx, phase)) + 'px ' +
				-Math.round(phase - mxUtils.mod(this.view.translate.y * this.view.scale + dy, phase)) + 'px';
			canvas.style.backgroundPosition = position;
		}
	};
	
	// Draws page breaks only within the page
	mxGraph.prototype.updatePageBreaks = function(visible, width, height)
	{
		var scale = this.view.scale;
		var tr = this.view.translate;
		var fmt = this.pageFormat;
		var ps = scale * this.pageScale;

		var bounds2 = this.view.getBackgroundPageBounds();

		width = bounds2.width;
		height = bounds2.height;
		var bounds = new mxRectangle(scale * tr.x, scale * tr.y, fmt.width * ps, fmt.height * ps);

		// Does not show page breaks if the scale is too small
		visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;

		var horizontalCount = (visible) ? Math.ceil(height / bounds.height) - 1 : 0;
		var verticalCount = (visible) ? Math.ceil(width / bounds.width) - 1 : 0;
		var right = bounds2.x + width;
		var bottom = bounds2.y + height;

		if (this.horizontalPageBreaks == null && horizontalCount > 0)
		{
			this.horizontalPageBreaks = [];
		}
		
		if (this.verticalPageBreaks == null && verticalCount > 0)
		{
			this.verticalPageBreaks = [];
		}
			
		var drawPageBreaks = mxUtils.bind(this, function(breaks)
		{
			if (breaks != null)
			{
				var count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount; 
				
				for (var i = 0; i <= count; i++)
				{
					var pts = (breaks == this.horizontalPageBreaks) ?
						[new mxPoint(Math.round(bounds2.x), Math.round(bounds2.y + (i + 1) * bounds.height)),
						 new mxPoint(Math.round(right), Math.round(bounds2.y + (i + 1) * bounds.height))] :
						[new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bounds2.y)),
						 new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bottom))];
					
					if (breaks[i] != null && breaks[i].node != null)
					{
						breaks[i].points = pts;
						breaks[i].redraw();
					}
					else
					{
						if (breaks[i] != null)
						{
							breaks[i].destroy();
						}

						var pageBreak = new mxPolyline(pts, this.pageBreakColor);
						pageBreak.dialect = this.dialect;
						pageBreak.isDashed = this.pageBreakDashed;
						pageBreak.pointerEvents = false;
						pageBreak.init(this.view.backgroundPane);
						pageBreak.redraw();

						breaks[i] = pageBreak;
					}
				}
				
				for (var i = count; i < breaks.length; i++)
				{
					if (breaks[i] != null)
					{
						breaks[i].destroy();
					}
				}
				
				breaks.splice(count, breaks.length - count);
			}
		});
			
		drawPageBreaks(this.horizontalPageBreaks);
		drawPageBreaks(this.verticalPageBreaks);
	};
	
	// Disables removing relative children and table rows and cells from parents
	var mxGraphHandlerShouldRemoveCellsFromParent = mxGraphHandler.prototype.shouldRemoveCellsFromParent;
	mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
	{
		for (var i = 0; i < cells.length; i++)
		{
			if (this.graph.isTableCell(cells[i]) || this.graph.isTableRow(cells[i]))
			{
				return false;
			}
			else if (this.graph.getModel().isVertex(cells[i]))
			{
				var geo = this.graph.getCellGeometry(cells[i]);
				
				if (geo != null && geo.relative)
				{
					return false;
				}
			}
		}
		
		return mxGraphHandlerShouldRemoveCellsFromParent.apply(this, arguments);
	};

	// Overrides to ignore hotspot only for target terminal
	var mxConnectionHandlerCreateMarker = mxConnectionHandler.prototype.createMarker;
	mxConnectionHandler.prototype.createMarker = function()
	{
		var marker = mxConnectionHandlerCreateMarker.apply(this, arguments);
		
		marker.intersects = mxUtils.bind(this, function(state, evt)
		{
			if (this.isConnecting())
			{
				return true;
			}
			
			return mxCellMarker.prototype.intersects.apply(marker, arguments);
		});
		
		return marker;
	};

	// Creates background page shape
	mxGraphView.prototype.createBackgroundPageShape = function(bounds)
	{
		return new mxRectangleShape(bounds, '#ffffff', this.graph.defaultPageBorderColor);
	};

	// Fits the number of background pages to the graph
	mxGraphView.prototype.getBackgroundPageBounds = function()
	{
		var gb = this.getGraphBounds();
		
		// Computes unscaled, untranslated graph bounds
		var x = (gb.width > 0) ? gb.x / this.scale - this.translate.x : 0;
		var y = (gb.height > 0) ? gb.y / this.scale - this.translate.y : 0;
		var w = gb.width / this.scale;
		var h = gb.height / this.scale;
		
		var fmt = this.graph.pageFormat;
		var ps = this.graph.pageScale;

		var pw = fmt.width * ps;
		var ph = fmt.height * ps;

		var x0 = Math.floor(Math.min(0, x) / pw);
		var y0 = Math.floor(Math.min(0, y) / ph);
		var xe = Math.ceil(Math.max(1, x + w) / pw);
		var ye = Math.ceil(Math.max(1, y + h) / ph);
		
		var rows = xe - x0;
		var cols = ye - y0;

		var bounds = new mxRectangle(this.scale * (this.translate.x + x0 * pw), this.scale *
				(this.translate.y + y0 * ph), this.scale * rows * pw, this.scale * cols * ph);
		
		return bounds;
	};
	
	// Add panning for background page in VML
	var graphPanGraph = mxGraph.prototype.panGraph;
	mxGraph.prototype.panGraph = function(dx, dy)
	{
		graphPanGraph.apply(this, arguments);
		
		if ((this.dialect != mxConstants.DIALECT_SVG && this.view.backgroundPageShape != null) &&
			(!this.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.container)))
		{
			this.view.backgroundPageShape.node.style.marginLeft = dx + 'px';
			this.view.backgroundPageShape.node.style.marginTop = dy + 'px';
		}
	};

	/**
	 * Consumes click events for disabled menu items.
	 */
	var mxPopupMenuAddItem = mxPopupMenu.prototype.addItem;
	mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled)
	{
		var result = mxPopupMenuAddItem.apply(this, arguments);
		
		if (enabled != null && !enabled)
		{
			mxEvent.addListener(result, 'mousedown', function(evt)
			{
				mxEvent.consume(evt);
			});
		}
		
		return result;
	};
	
	/**
	 * Selects tables before cells and rows.
	 */
	var mxGraphHandlerIsPropagateSelectionCell = mxGraphHandler.prototype.isPropagateSelectionCell;
	mxGraphHandler.prototype.isPropagateSelectionCell = function(cell, immediate, me)
	{
		var result = false;
		var parent = this.graph.model.getParent(cell)
		
		if (immediate)
		{
			var geo = (this.graph.model.isEdge(cell)) ? null :
				this.graph.getCellGeometry(cell);
			
			result = !this.graph.model.isEdge(parent) &&
				!this.graph.isSiblingSelected(cell) &&
				((geo != null && geo.relative) ||
				!this.graph.isContainer(parent) ||
				this.graph.isPart(cell));
		}
		else
		{
			result = mxGraphHandlerIsPropagateSelectionCell.apply(this, arguments);
			
			if (this.graph.isTableCell(cell) || this.graph.isTableRow(cell))
			{
				var table = parent;
				
				if (!this.graph.isTable(table))
				{
					table = this.graph.model.getParent(table);
				}
				
				result = !this.graph.selectionCellsHandler.isHandled(table) ||
					(this.graph.isCellSelected(table) && this.graph.isToggleEvent(me.getEvent())) ||
					(this.graph.isCellSelected(cell) && !this.graph.isToggleEvent(me.getEvent())) ||
					(this.graph.isTableCell(cell) && this.graph.isCellSelected(parent));
			}
		}
		
		return result;
	};

	/**
	 * Returns last selected ancestor
	 */
	mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
	{
		var cell = me.getCell();
		var model = this.graph.getModel();
		var parent = model.getParent(cell);
		var state = this.graph.view.getState(parent);
		var selected = this.graph.isCellSelected(cell);
		
		while (state != null && (model.isVertex(parent) || model.isEdge(parent)))
		{
			var temp = this.graph.isCellSelected(parent);
			selected = selected || temp;
			
			if (temp || (!selected && (this.graph.isTableCell(cell) ||
				this.graph.isTableRow(cell))))
			{
				cell = parent;
			}
			
			parent = model.getParent(parent);
		}
		
		return cell;
	};

})();
