var mxIsElectron = navigator.userAgent != null &&	navigator.userAgent.toLowerCase().indexOf(' electron/') > -1;var GOOGLE_APPS_MAX_AREA = 25000000;var GOOGLE_SHEET_MAX_AREA = 1048576; //1024x1024//TODO Add support for loading math from a local folderEditor.initMath((remoteMath? 'https://app.diagrams.net/' : '') + 'math/MathJax.js');function render(data){	var autoScale = false;		if (data.scale == 'auto')	{		autoScale = true;		data.scale = 1;	}	// BUG: CWE-94 Improper Control of Generation of Code ('Code Injection')	// document.body.innerHTML = '';	// FIXED:	document.body.innerText = '';	var container = document.createElement('div');	container.id = 'graph';	container.style.width = '100%';	container.style.height = '100%';	document.body.appendChild(container);		var graph = new Graph(container);	data.border = parseInt(data.border) || 0;	data.w = parseFloat(data.w) || 0;	data.h = parseFloat(data.h) || 0;	data.scale = parseFloat(data.scale) || 1;		var extras = null;		try	{		extras = JSON.parse(data.extras);	} 	catch (e)	{		try 		{			extras = JSON.parse(decodeURIComponent(data.extras));		}		catch (e)		{			// ignore		}	}	var gridColor = null;		if (extras != null && extras.grid != null)	{		graph.gridSize = extras.grid.size;		graph.view.gridSteps = extras.grid.steps;		gridColor = extras.grid.color;	}		if (extras != null && extras.diagramLanguage != null)	{		Graph.diagramLanguage = extras.diagramLanguage;		Graph.translateDiagram = true;	}		//PNG+XML format	if (data.xml.substring(0, 5) == 'iVBOR' || (extras != null && extras.isPng))	{		data.xml = Editor.extractGraphModelFromPng('data:image/png;base64,' + data.xml);	}		//IE11 sends incorrect xml	if (data.xml.substring(0, 11) == '<#document>')	{		data.xml = data.xml.substring(11, data.xml.length - 12);	}		// Parses XML	var doc = mxUtils.parseXml(data.xml);	var node = Editor.extractGraphModel(doc.documentElement, true);	if (node == null)	{		//Electron pdf export		try 		{			electron.sendMessage('render-finished', null);		}		catch(e)		{			console.log(e);		}				return graph;	}		var xmlDoc = node.ownerDocument;	var origXmlDoc = xmlDoc;	var diagrams = null;	var from = 0;	function getFileXml(uncompressed)	{		var xml = mxUtils.getXml(origXmlDoc);		EditorUi.prototype.createUi = function(){};		EditorUi.prototype.addTrees = function(){};		EditorUi.prototype.updateActionStates = function(){};		var editorUi = new EditorUi();		var tmpFile = new LocalFile(editorUi, xml);		editorUi.setCurrentFile(tmpFile);		editorUi.setFileData(xml);		return editorUi.createFileData(editorUi.getXmlFileData(null, null, uncompressed));	};	if (mxIsElectron && data.format == 'xml')	{		try		{			electron.sendMessage('xml-data', getFileXml(data.uncompressed));		}		catch(e)		{			electron.sendMessage('xml-data-error');		}				return;	}	// Handles mxfile	if (xmlDoc.documentElement.nodeName == 'mxfile')	{		diagrams = xmlDoc.documentElement.getElementsByTagName('diagram');	}		//Add global variables to graph	if (extras != null && extras.globalVars != null)	{		graph.globalVars = extras.globalVars;	}	/**	 * Disables custom links on shapes.	 */	var graphGetLinkForCell = graph.getLinkForCell;		graph.getLinkForCell = function(cell)	{		var link = graphGetLinkForCell.apply(this, arguments);				if (link != null && this.isCustomLink(link))		{			link = null;		}				return link;	};		/**	 * Disables custom links in labels.	 */	var cellRendererRedrawLabelShape = graph.cellRenderer.redrawLabelShape;		graph.cellRenderer.redrawLabelShape = function(shape)	{		cellRendererRedrawLabelShape.apply(this, arguments);				if (shape.node != null)		{			var links = shape.node.getElementsByTagName('a');			for (var i = 0; i < links.length; i++)			{				var href = links[i].getAttribute('href');								if (href != null && graph.isCustomLink(href))				{					links[i].setAttribute('href', '#');				}			}			}	};		var preview = null;	var waitCounter = 1;	var bounds;	var pageId;	var expScale;	// Waits for all images to finish loading	var cache = new Object();	var math = false;		// Decrements waitCounter and invokes callback when finished	function decrementWaitCounter()	{		if (--waitCounter < 1)		{			//Note: This code targets Chrome as it is the browser used by export server			//Ensure that all fonts has been loaded, this promise is never rejected			document.fonts.ready.then(function() 			{				var doneDiv = document.createElement("div");				var pageCount = diagrams != null? diagrams.length : 1;				doneDiv.id = 'LoadingComplete';				doneDiv.style.display = 'none';				doneDiv.setAttribute('bounds', JSON.stringify(bounds));				doneDiv.setAttribute('page-id', pageId);				doneDiv.setAttribute('scale', expScale);				doneDiv.setAttribute('pageCount', pageCount);				document.body.appendChild(doneDiv);				//Electron pdf export				if (mxIsElectron)				{					try 					{						electron.registerMsgListener('get-svg-data', (arg) => 						{							graph.mathEnabled = math; //Enable math such that getSvg works as expected							// Returns the exported SVG for the given graph (see EditorUi.exportSvg)							var bg = graph.background;															if (bg == mxConstants.NONE)							{								bg = null;							}														var svgRoot = graph.getSvg(bg, 1, 0, false, null, true, null, null, null);														if (graph.shadowVisible)							{								graph.addSvgShadow(svgRoot);							}														// TODO addFontCss cannot be used as it requires this							// Adds CSS							//Editor.prototype.addFontCss(svgRoot);														if (math)							{								Editor.prototype.addMathCss(svgRoot);							}													function doSend() 							{								var editable = data.embedXml == '1';								if (editable)								{									svgRoot.setAttribute('content', getFileXml());								}								electron.sendMessage('svg-data', Graph.xmlDeclaration + '\n' + ((editable) ? Graph.svgFileComment + '\n' : '') +															 Graph.svgDoctype + '\n' + mxUtils.getXml(svgRoot));							};							if (data.embedImages == '1')							{								var tmpEditor = new Editor();								tmpEditor.convertImages(svgRoot, doSend);							}							else							{								doSend();							}						});												//For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope						electron.sendMessage('render-finished', {bounds: JSON.stringify(bounds), pageCount: pageCount});					}					catch(e)					{						console.log(e);					}				}			});		}	};		function waitForImages(tagName, attributeName)	{		var imgs = document.body.getElementsByTagName(tagName);		waitCounter += imgs.length;		for (var i = 0; i < imgs.length; i++)		{			// No load events for image elements in Phantom using indirection instead			var src = imgs[i].getAttribute(attributeName);						if (src != null && src.length > 0 && cache[src] == null)			{				cache[src] = new Image();				cache[src].onload = decrementWaitCounter;				cache[src].onerror = decrementWaitCounter;				cache[src].src = src;			}			else			{				decrementWaitCounter();			}		}	};		// Waits for MathJax.Hub to become available to register	// wait counter callback asynchronously after math render	var editorDoMathJaxRender = Editor.doMathJaxRender;		Editor.doMathJaxRender = function(container)	{		editorDoMathJaxRender.apply(this, arguments);				window.setTimeout(function()		{			window.MathJax.Hub.Queue(function ()			{				decrementWaitCounter();			});		}, 0);	};		// Adds async MathJax rendering task	function renderMath(elt)	{		if (math && Editor.MathJaxRender != null)		{			waitCounter++;			Editor.MathJaxRender(elt);		}	};	function loadExtFonts(extFonts)	{		try		{			extFonts = extFonts.split('|').map(function(ef)			{				var parts = ef.split('^');				return {name: parts[0], url: parts[1]};			});		}		catch(e)		{			//ignore and return!			return;		}				waitCounter += extFonts.length;		//Note: This code targets Chrome as it is the browser used by export server		for (var i = 0; i < extFonts.length; i++)		{			if (extFonts[i].url.indexOf(Editor.GOOGLE_FONTS) == 0)			{				var link = document.createElement('link');								link.setAttribute('rel', 'stylesheet');				link.setAttribute('charset', 'UTF-8');				link.setAttribute('type', 'text/css');								link.onload = decrementWaitCounter;				link.onerror = decrementWaitCounter;							link.setAttribute('href', extFonts[i].url);				var head = document.getElementsByTagName('head')[0];				head.appendChild(link);			}			else			{				//Relative urls doesn't work				if (extFonts[i].url.indexOf(PROXY_URL) == 0 && PROXY_URL.indexOf('http') == -1)				{					var href = window.location.href;					href = href.substring(0, href.lastIndexOf('/') + 1);					extFonts[i].url = href + extFonts[i].url;				}								var font = new FontFace(extFonts[i].name, 'url(' + extFonts[i].url + ')');								font.load().then(function(loadedFont)				{					document.fonts.add(loadedFont);					decrementWaitCounter();				}).catch(decrementWaitCounter);			}		}	};	function renderGrid()	{		if (gridColor == null) return;					var view = graph.view;		var gridImage = btoa(unescape(encodeURIComponent(view.createSvgGrid(gridColor))));		gridImage = 'url(' + 'data:image/svg+xml;base64,' + gridImage + ')';		var phase = graph.gridSize * view.gridSteps * view.scale;				var x0 = 0;		var y0 = 0;				if (view.backgroundPageShape != null)		{			var bds = view.getBackgroundPageBounds();						x0 = 1 + bds.x;			y0 = 1 + bds.y;		}				// Computes the offset to maintain origin for grid		var position = -Math.round(phase - mxUtils.mod(view.translate.x * view.scale - x0, phase)) + 'px ' +			-Math.round(phase - mxUtils.mod(view.translate.y * view.scale - y0, phase)) + 'px';				var pages = document.querySelectorAll('[id^=mxPage]');				var cssTxt = 'margin: 0;padding: 0;background-image: ' + gridImage + ';background-position: ' + position;		document.body.style.cssText = cssTxt;		for (var i = 0; i < pages.length; i++)		{			pages[i].style.cssText = cssTxt;		}	};		var origAddFont = Graph.addFont;		Graph.addFont = function(name, url)	{		waitCounter++;		return origAddFont.call(this, name, url, decrementWaitCounter);		};			function renderPage()	{		// Enables math typesetting		math |= xmlDoc.documentElement.getAttribute('math') == '1';				//Load external fonts		var extFonts = xmlDoc.documentElement.getAttribute('extFonts');				if (extFonts)		{			loadExtFonts(extFonts);		}				// Configure graph		graph.foldingEnabled = false;		graph.setEnabled(false);				// Sets background image		var bgImg = xmlDoc.documentElement.getAttribute('backgroundImage');		if (bgImg != null)		{			bgImg = JSON.parse(bgImg);			graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width,				bgImg.height, bgImg.x, bgImg.y));		}				// Parses XML into graph		var codec = new mxCodec(xmlDoc);		var model = graph.getModel();		codec.decode(xmlDoc.documentElement, model);		var bg;				if (data.format == 'pdf')		{			if (data.bg == 'none')			{				bg = null;				}			else			{				bg = xmlDoc.documentElement.getAttribute('background');								if (bg == 'none' || !bg)				{					bg = '#ffffff';				}			}		}		else		{			// Loads background color			bg = (data.bg != null && data.bg.length > 0) ?				data.bg : xmlDoc.documentElement.getAttribute('background');			// Normalizes values for transparent backgrounds			if (bg == 'none' || bg == '')			{				bg = null;			}						// Checks if export format supports transparent backgrounds			if (bg == null && data.format != 'gif' && data.format != 'png' && data.format != 'svg')			{				bg = '#ffffff';			}			}				// Sets background color on page		if (bg != null)		{			document.body.style.backgroundColor = bg;		}				//handle layers		if (extras != null && ((extras.layers != null && extras.layers.length > 0) || 							   (extras.layerIds != null && extras.layerIds.length > 0)))		{			var childCount = model.getChildCount(model.root);						// Hides all layers			for (var i = 0; i < childCount; i++)			{				model.setVisible(model.getChildAt(model.root, i), false);			}			if (extras.layerIds != null)			{				for (var i = 0; i < extras.layerIds.length; i++)				{					model.setVisible(model.getCell(extras.layerIds[i]), true);				}			}			else			{				for (var i = 0; i < extras.layers.length; i++)				{					var layer = model.getChildAt(model.root, extras.layers[i]);										if (layer != null)					{						model.setVisible(layer, true);					}				}			}		}				// Sets initial value for PDF page background		graph.pdfPageVisible = false;				// Handles PDF output where the output should match the page format if the page is visible		if (data.print || (data.format == 'pdf' && xmlDoc.documentElement.getAttribute('page') == '1' && data.w == 0 && data.h == 0 && data.scale == 1))		{			//Electron printing			var printScale = 1;						if (data.print)			{				document.title = data.fileTitle;								var gb = graph.getGraphBounds();				printScale = data.pageScale;						if (isNaN(printScale))				{					printScale = 1;				}								if (data.fit)				{					var h = parseInt(data.sheetsAcross);					var v = parseInt(data.sheetsDown);										data.scale = Math.min((data.pageHeight * v) / (gb.height / graph.view.scale),							(data.pageWidth * h) / (gb.width / graph.view.scale));				}				else				{					data.scale = data.scale / graph.pageScale;										if (isNaN(data.scale))					{						printScale = 1 / graph.pageScale;					}				}			}						var pw = data.pageWidth || xmlDoc.documentElement.getAttribute('pageWidth');			var ph = data.pageHeight || xmlDoc.documentElement.getAttribute('pageHeight');			graph.pdfPageVisible = true;						if (pw != null && ph != null)			{				graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph));			}						var ps = data.pageScale || xmlDoc.documentElement.getAttribute('pageScale');						if (ps != null)			{				graph.pageScale = ps;			}						graph.getPageSize = function()			{				return new mxRectangle(0, 0, this.pageFormat.width * this.pageScale,					this.pageFormat.height * this.pageScale);			};						graph.getPageLayout = function()			{				var size = this.getPageSize();				var bounds = this.getGraphBounds();				if (bounds.width == 0 || bounds.height == 0)				{					return new mxRectangle(0, 0, 1, 1);				}				else				{					// Computes untransformed graph bounds					var x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);					var y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);					var w = Math.floor(bounds.width / this.view.scale);					var h = Math.floor(bounds.height / this.view.scale);										var x0 = Math.floor(x / size.width);					var y0 = Math.floor(y / size.height);					var w0 = Math.ceil((x + w) / size.width) - x0;					var h0 = Math.ceil((y + h) / size.height) - y0;										return new mxRectangle(x0, y0, w0, h0);				}			};			// Fits the number of background pages to the graph			graph.view.getBackgroundPageBounds = function()			{				var layout = this.graph.getPageLayout();				var page = this.graph.getPageSize();								return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width),					this.scale * (this.translate.y + layout.y * page.height),					this.scale * layout.width * page.width,					this.scale * layout.height * page.height);			};		}		if (!graph.pdfPageVisible)		{			var b = graph.getGraphBounds();						// Floor is needed to keep rendering crisp			if (data.w > 0 || data.h > 0)			{				var s = 1;								if (data.w > 0 && data.h > 0)				{					s = Math.min(data.w / b.width, data.h / b.height);				}				else if (data.w > 0)				{					s = data.w / b.width;				}				else				{					s = data.h / b.height;				}								graph.view.scaleAndTranslate(s,					Math.floor(data.border / s - Math.floor(b.x)),					Math.floor(data.border / s - Math.floor(b.y)));			}			else			{				var s = data.scale;								if (autoScale)				{					var pageWidth = (extras != null && extras.pageWidth != null) ? extras.pageWidth : 800;										if (b.width < pageWidth & b.height < 1.5 * pageWidth)					{						s = 4;					}					else if (b.width < 2 * pageWidth & b.height < 3 * pageWidth)					{						s = 3;					}					else if (b.width < 4 * pageWidth && b.height < 6 * pageWidth)					{						s = 2;					}										if (extras != null && extras.isGoogleSheet != null)					{						GOOGLE_APPS_MAX_AREA = GOOGLE_SHEET_MAX_AREA;					}										//The image cannot exceed 25 MP to be included in Google Apps					if (b.width * s * b.height * s > GOOGLE_APPS_MAX_AREA)					{						//Subtracting 0.01 to prevent any other rounding that can make slightly over 25 MP 						s = Math.sqrt(GOOGLE_APPS_MAX_AREA / (b.width * b.height)) - 0.01;					}				}								graph.view.scaleAndTranslate(s,					Math.floor(data.border - Math.floor(b.x)),					Math.floor(data.border - Math.floor(b.y)));			}		}		else		{			// Disables border for PDF page export			data.border = 0;						// Moves to first page in page layout			var layout = graph.getPageLayout();			var page = graph.getPageSize();			var dx = layout.x * page.width;			var dy = layout.y * page.height;						if (dx != 0 || dy != 0)			{				graph.view.setTranslate(Math.floor(-dx), Math.floor(-dy));			}		}				// Gets the diagram bounds and sets the document size		bounds = (graph.pdfPageVisible) ? graph.view.getBackgroundPageBounds() : graph.getGraphBounds();		bounds.width = Math.ceil(bounds.width + data.border) + 1; //The 1 extra pixels to prevent cutting the cells on the edges when crop is enabled		bounds.height = Math.ceil(bounds.height + data.border) + 1; //The 1 extra pixels to prevent starting a new page. TODO Not working in every case				//Print to pdf fails for 1x1 pages		if (bounds.width <= 1 && bounds.height <= 1)		{			bounds.width = 2;			bounds.height = 2;		}		expScale = graph.view.scale || 1;				// Converts the graph to a vertical sequence of pages for PDF export		if (graph.pdfPageVisible)		{			var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;			var scale = data.print? data.scale : 1 / graph.pageScale;			var autoOrigin = (data.print && data.fit != null) ? data.fit : false;			var border = 0;			// Negative coordinates are cropped or shifted if page visible			var gb = graph.getGraphBounds();			var x0 = 0;			var y0 = 0;				// Applies print scale			pf = mxRectangle.fromRectangle(pf);			pf.width = Math.ceil(pf.width * printScale) + 1; //The 1 extra pixels to prevent cutting the cells on the right edge of the page			pf.height = Math.ceil(pf.height * printScale) + 1; //The 1 extra pixels to prevent starting a new page. TODO Not working in every case			scale *= printScale;							// Starts at first visible page			if (!autoOrigin)			{				var layout = graph.getPageLayout();				x0 -= layout.x * pf.width;				y0 -= layout.y * pf.height;			}						if (preview == null)			{				preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);				preview.printBackgroundImage = true;				preview.autoOrigin = autoOrigin;				preview.backgroundColor = bg;				// Renders print output into this document and removes the graph container				preview.open(null, window);				graph.container.parentNode.removeChild(graph.container);			}			else			{				preview.backgroundColor = bg;				preview.autoOrigin = autoOrigin; 				preview.appendGraph(graph, scale, x0, y0);			}			// Adds shadow			// NOTE: Shadow rasterizes output			/*if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')			{				var svgs = document.getElementsByTagName('svg');								for (var i = 0; i < svgs.length; i++)				{					var svg = svgs[i];					var filter = graph.addSvgShadow(svg, null, true);					filter.setAttribute('id', 'shadow-' + i);					svg.appendChild(filter);					svg.setAttribute('filter', 'url(#' + 'shadow-' + i + ')');				}								border = 7;			}*/						bounds = new mxRectangle(0, 0, pf.width, pf.height);		}		else		{			var bgImg = graph.backgroundImage;			if (bgImg != null)			{				var t = graph.view.translate;				var s = graph.view.scale;				bounds.add(new mxRectangle(					(t.x + bgImg.x) * s, (t.y + bgImg.y) * s,					bgImg.width * s, bgImg.height * s));				if (t.x < 0 || t.y < 0)				{					graph.view.setTranslate(t.x < 0? -bgImg.x * s : t.x, t.y < 0? -bgImg.y * s : t.y);					bounds.x = 0.5;					bounds.y = 0.5;				}			}			// Adds shadow			// NOTE: PDF shadow rasterizes output so it's disabled			if (data.format != 'pdf' && mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')			{				graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);				graph.setShadowVisible(true);				bounds.width += 7;				bounds.height += 7;			}						document.body.style.width = Math.ceil(bounds.x + bounds.width) + 'px';			document.body.style.height = Math.ceil(bounds.y + bounds.height) + 'px';		}	};		if (diagrams != null && diagrams.length > 0)	{		var to = diagrams.length - 1;				//Parameters to and all pages should not be sent with formats other than PDF with page view enabled		if (!data.allPages)		{			if (data.pageId != null)			{				for (var i = 0; i < diagrams.length; i++)				{					if (data.pageId == diagrams[i].getAttribute('id'))					{						from = i;						to = i;						break;					}				}			}			else			{				from = Math.max(0, Math.min(parseInt(data.from) || from, diagrams.length - 1));				to = parseInt(data.to);				//If to is not defined, use from (so one page), otherwise, to is restricted to the range from "from" to diagrams.length - 1				to = isNaN(to)? from : Math.max(from, Math.min(to, diagrams.length - 1));			}		}				/**		 * Implements %page% and %pagenumber% placeholders		 */		var graphGetGlobalVariable = graph.getGlobalVariable;				graph.getGlobalVariable = function(name)		{			if (name == 'page')			{				return (diagrams == null) ? 'Page-1' :					(diagrams[from].getAttribute('name') || ('Page-' + (from + 1)));			}			else if (name == 'pagenumber')			{				return from + 1;			}						return graphGetGlobalVariable.apply(this, arguments);		};					for (var i = from; i <= to; i++) 		{			if (diagrams[i] != null)			{				if (pageId == null)				{					pageId = diagrams[i].getAttribute('id')				}								xmlDoc = Editor.parseDiagramNode(diagrams[i]);								if (xmlDoc != null)				{					xmlDoc = xmlDoc.ownerDocument;				}				graph.getModel().clear();				from = i;				renderPage();			}		}	}	else	{		renderPage();	}		if (fallbackFont)	{		//Add a fallbackFont font to all labels in case the selected font doesn't support the character		//Some systems doesn't have a good fallback fomt that supports all languages		//Use this with a custom font-face in export-fonts.css file		document.querySelectorAll('foreignObject div').forEach(d => d.style.fontFamily = (d.style.fontFamily || '') + ', ' + fallbackFont);	}		renderGrid();	// Includes images in SVG and HTML labels	waitForImages('image', 'xlink:href');	waitForImages('img', 'src');	renderMath(document.body);	// Immediate return if not waiting for any content	decrementWaitCounter();		return graph;};//Electron pdf exportif (mxIsElectron){	try 	{		electron.registerMsgListener('render', (arg) => 		{			try			{				render(arg);			}			catch(e)			{				console.log(e);				electron.sendMessage('render-finished', null);			}		});	}	catch(e)	{		console.log(e);	}}