1function mxGraphMlCodec()
2{
3	this.cachedRefObj = {};
4};
5
6
7mxGraphMlCodec.prototype.refRegexp = /^\{y\:GraphMLReference\s+(\d+)\}$/;
8mxGraphMlCodec.prototype.staticRegexp = /^\{x\:Static\s+(.+)\.(.+)\}$/;
9
10mxGraphMlCodec.prototype.decode = function (xml, callback, onError)
11{
12	try
13	{
14		var doc = mxUtils.parseXml(xml);
15
16		var graphs = this.getDirectChildNamedElements(doc.documentElement, mxGraphMlConstants.GRAPH);
17
18		this.initializeKeys(doc.documentElement);
19
20		var mxFile = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mxfile>";
21		for (var i = 0; i < graphs.length; i++)
22		{
23			var pageElement = graphs[i];
24
25			var graph = this.createMxGraph();
26			var model = graph.getModel();
27
28	        model.beginUpdate();
29	        try
30	        {
31		        this.nodesMap = {};
32		    	this.edges = [];
33		        this.importGraph(pageElement, graph, graph.getDefaultParent());
34
35		    	for (var i = 0; i < this.edges.length; i++)
36				{
37		    		var edgesObj = this.edges[i];
38		    		var edges = edgesObj.edges;
39		    		var parent = edgesObj.parent;
40		    		var dx = edgesObj.dx, dy = edgesObj.dy;
41
42			    	for (var j = 0; j < edges.length; j++)
43			    	{
44			    		this.importEdge(edges[j], graph, parent, dx, dy);
45			    	}
46				}
47	        }
48	        catch(e)
49	        {
50	        	console.log(e);
51	        	throw e;
52	        }
53	        finally
54	        {
55	        	model.endUpdate();
56	        }
57
58	    	//update edges' labels to convert their labels relative coordinate to ours
59	        model.beginUpdate();
60	        try
61	        {
62	        	var cells = graph.getModel().cells;
63	        	var tr = graph.view.translate;
64
65	        	for (var id in cells)
66	    		{
67	        		var edge = cells[id];
68
69	        		if (edge.edge && edge.getChildCount() > 0)
70	    			{
71	        			for (var i = 0; i < edge.getChildCount(); i++)
72	    				{
73	        				var cell = edge.children[i];
74	                		var geo = cell.geometry;
75
76	                		if (!geo.adjustIt) continue;
77
78		        			var state = graph.view.getState(edge);
79		        			var abdPs = state.absolutePoints;
80		        			var p0 = abdPs[0];
81		        			var pe = abdPs[abdPs.length - 1];
82
83		        			var ratio = geo.x;
84		        			var dist = geo.y;
85		        			var dx = pe.x - p0.x
86		        			var dy = pe.y - p0.y
87
88		        			var x = p0.x + ratio * dx;
89		        			var y = p0.y + ratio * dy;
90
91		        			var d = Math.sqrt(dx*dx + dy*dy);
92		        			dx /= d;
93		        			dy /= d;
94
95		        			x -= dist * dy;
96		        			y += dist * dx;
97
98		        			var np = graph.view.getRelativePoint(state, x, y);
99		        			geo.x = np.x;
100		        			geo.y = np.y;
101		    			}
102		    		}
103	    		}
104	        }
105	        catch(e)
106	        {
107	        	console.log(e);
108	        	throw e;
109	        }
110	        finally
111	        {
112	        	model.endUpdate();
113	        }
114
115	        mxFile += this.processPage(graph, i+1);
116		}
117
118		mxFile += "</mxfile>";
119
120		if (callback)
121		{
122			callback(mxFile);
123		}
124	}
125    catch(e)
126    {
127    	if (onError)
128    	{
129    		onError(e);
130    	}
131    }
132};
133
134mxGraphMlCodec.prototype.initializeKeys = function (graphmlElement)
135{
136	var keys = this.getDirectChildNamedElements(graphmlElement, mxGraphMlConstants.KEY);
137
138	this.nodesKeys = {};
139	this.edgesKeys = {};
140	this.portsKeys = {};
141	this.sharedData = {};
142
143	this.nodesKeys[mxGraphMlConstants.NODE_GEOMETRY] = {};
144	this.nodesKeys[mxGraphMlConstants.USER_TAGS] = {};
145	this.nodesKeys[mxGraphMlConstants.NODE_STYLE] = {};
146	this.nodesKeys[mxGraphMlConstants.NODE_LABELS] = {};
147	this.nodesKeys[mxGraphMlConstants.NODE_GRAPHICS] = {};
148	this.edgesKeys[mxGraphMlConstants.EDGE_GEOMETRY] = {};
149	this.edgesKeys[mxGraphMlConstants.EDGE_STYLE] = {};
150	this.edgesKeys[mxGraphMlConstants.EDGE_LABELS] = {};
151	this.portsKeys[mxGraphMlConstants.PORT_LOCATION_PARAMETER] = {};
152	this.portsKeys[mxGraphMlConstants.PORT_STYLE] = {};
153	this.portsKeys[mxGraphMlConstants.PORT_VIEW_STATE] = {};
154
155	var sharedDataId;
156
157	for (var i = 0; i < keys.length; i++)
158	{
159		var keyObj = this.dataElem2Obj(keys[i]);
160
161		var id = keyObj[mxGraphMlConstants.ID];
162		var _for = keyObj[mxGraphMlConstants.KEY_FOR];
163		var attName = keyObj[mxGraphMlConstants.KEY_NAME];
164		var yType = keyObj[mxGraphMlConstants.KEY_YTYPE];
165
166		if (attName == mxGraphMlConstants.SHARED_DATA) sharedDataId = id;
167
168		attName = attName? attName : yType
169
170		//TODO handle the defaults inside these keys
171		switch (_for)
172		{
173			case mxGraphMlConstants.NODE:
174				this.nodesKeys[attName] = {key: id, keyObj: keyObj};
175			break;
176			case mxGraphMlConstants.EDGE:
177				this.edgesKeys[attName] = {key: id, keyObj: keyObj};
178			break;
179			case mxGraphMlConstants.PORT:
180				this.portsKeys[attName] = {key: id, keyObj: keyObj};
181			break;
182			case mxGraphMlConstants.ALL:
183				var obj = {key: id, keyObj: keyObj};
184				this.nodesKeys[attName] = obj;
185				this.edgesKeys[attName] = obj;
186				this.portsKeys[attName] = obj;
187			break;
188		}
189	}
190
191	var data = this.getDirectChildNamedElements(graphmlElement, mxGraphMlConstants.DATA);
192
193	for (var i = 0; i < data.length; i++)
194	{
195		var key = data[i].getAttribute(mxGraphMlConstants.KEY);
196
197		if (key == sharedDataId)
198		{
199			var sharedData = this.getDirectChildNamedElements(data[i], mxGraphMlConstants.Y_SHARED_DATA);
200
201			for (var j = 0; j < sharedData.length; j++)
202			{
203				var dataItems = this.getDirectChildElements(sharedData[j]);
204
205				for (var k = 0; k < dataItems.length; k++)
206				{
207					var dkey = dataItems[k].getAttribute(mxGraphMlConstants.X_KEY);
208					this.sharedData[dkey] = dataItems[k];
209				}
210			}
211		}
212		else
213		{
214			var resources = this.getDirectChildNamedElements(data[i], mxGraphMlConstants.Y_RESOURCES);
215
216			for (var j = 0; j < resources.length; j++)
217			{
218				var dataItems = this.getDirectChildElements(resources[j]);
219
220				for (var k = 0; k < dataItems.length; k++)
221				{
222					var dkey = dataItems[k].getAttribute(mxGraphMlConstants.ID);
223					this.sharedData[dkey] = dataItems[k];
224				}
225			}
226		}
227	}
228};
229
230mxGraphMlCodec.prototype.parseAttributes = function (elem, obj)
231{
232	var atts = elem.attributes;
233	if (atts)
234	{
235
236		for (var i = 0; i < atts.length; i++)
237		{
238			var val = atts[i].nodeValue;
239			var ref = this.refRegexp.exec(val);
240			var staticMem = this.staticRegexp.exec(val);
241
242			if (ref)
243			{
244				var key = ref[1];
245				var subObj = this.cachedRefObj[key];
246
247				//already cached
248				if (!subObj)
249				{
250					subObj = {};
251					subObj[this.sharedData[key].nodeName] = this.dataElem2Obj(this.sharedData[key]);
252					this.cachedRefObj[key] = subObj;
253				}
254
255				obj[atts[i].nodeName] = subObj;
256			}
257			else if (staticMem)
258			{
259				obj[atts[i].nodeName] = {};
260				obj[atts[i].nodeName][staticMem[1]] = staticMem[2];
261			}
262			else
263			{
264				obj[atts[i].nodeName] = val;
265			}
266		}
267	}
268};
269
270mxGraphMlCodec.prototype.dataElem2Obj = function (elem)
271{
272	var ref = this.getDirectFirstChildNamedElements(elem, mxGraphMlConstants.GRAPHML_REFERENCE)
273					|| elem.getAttribute(mxGraphMlConstants.REFID);
274	var refKey = null;
275	var origElem = elem;
276	var obj = {};
277
278	if (ref)
279	{
280		var key = (typeof ref === "string")? ref : ref.getAttribute(mxGraphMlConstants.RESOURCE_KEY);
281		var cachedObj = this.cachedRefObj[key];
282
283		//already cached
284		if (cachedObj)
285		{
286			//parse all attributes to update the reference
287			this.parseAttributes(elem, cachedObj);
288			return cachedObj;
289		}
290
291		elem = this.sharedData[key];
292		refKey = key;
293	}
294
295	//parse all attributes
296	this.parseAttributes(elem, obj);
297
298	for (var i = 0; i < elem.childNodes.length; i++)
299	{
300		var child = elem.childNodes[i];
301
302		if (child.nodeType == 1)
303		{
304			var attName = child.nodeName;
305
306			//Special types of node (x:List and x:Static)
307			if (attName == mxGraphMlConstants.X_LIST)
308			{
309				var arr = [];
310				var arrayElem = this.getDirectChildElements(child);
311
312				for (var j = 0; j < arrayElem.length; j++)
313				{
314					attName = arrayElem[j].nodeName;
315					arr.push(this.dataElem2Obj(arrayElem[j]));
316				}
317
318				obj[attName] = arr;
319			}
320			else if (attName == mxGraphMlConstants.X_STATIC)
321			{
322				var member = child.getAttribute(mxGraphMlConstants.MEMBER);
323				var dotPos = member.lastIndexOf('.');
324				obj[member.substr(0, dotPos)] = member.substr(dotPos + 1);
325			}
326			else
327			{
328				var dotPos = attName.lastIndexOf(".");
329
330				if (dotPos > 0)
331				{
332					attName = attName.substr(dotPos + 1);
333				}
334
335				if (obj[attName] != null)
336				{
337					if (!(obj[attName] instanceof Array))
338					{
339						obj[attName] = [obj[attName]];
340					}
341
342					obj[attName].push(this.dataElem2Obj(child));
343				}
344				else
345				{
346					obj[attName] = this.dataElem2Obj(child);
347				}
348			}
349		}
350		else if ((child.nodeType == 3 || child.nodeType == 4) && child.textContent.trim())
351		{
352			obj["#text"] = child.textContent;
353		}
354	}
355
356	//cache referenced objects
357	if (refKey)
358	{
359		var tmpObj = {};
360		//parse all attributes before following the reference
361		this.parseAttributes(origElem, tmpObj);
362		tmpObj[this.sharedData[refKey].nodeName] = obj;
363		this.cachedRefObj[refKey] = tmpObj;
364		return tmpObj;
365	}
366
367	return obj;
368};
369
370mxGraphMlCodec.prototype.mapArray = function(arr, mapping, map)
371{
372	var obj = {};
373	for (var k = 0; k < arr.length; k++)
374	{
375		if (arr[k].name)
376		{
377			obj[arr[k].name] = arr[k].value || arr[k];
378		}
379	}
380	this.mapObject(obj, mapping, map);
381}
382//Use mapping information to fill the map based on obj content
383//TODO yjs looks like they need special handling
384mxGraphMlCodec.prototype.mapObject = function (obj, mapping, map)
385{
386	//defaults can be overridden by actual values later
387	if (mapping.defaults)
388	{
389		for (var key in mapping.defaults)
390		{
391			map[key] = mapping.defaults[key];
392		}
393	}
394
395	for (var key in mapping)
396	{
397		var parts = key.split('.');
398
399		var val = obj;
400
401		for (var i = 0; i < parts.length; i++)
402		{
403			if (!val) break;
404
405			val = val[parts[i]];
406		}
407
408		if (val == null && obj) //some vals doesn't need to be split
409		{
410			val = obj[key];
411		}
412
413		if (val != null)
414		{
415			var mappingObj = mapping[key];
416			if (typeof val === "string")
417			{
418				if (typeof mappingObj === "string")
419				{
420					map[mappingObj] = val.toLowerCase();
421				}
422				else if (typeof mappingObj === "object")
423				{
424					var modVal = val.toLowerCase();
425					switch(mappingObj.mod)
426					{
427						case "color": //mxGraph support alfa in colors in the standard format
428							if (val.indexOf("#") == 0 && val.length == 9)
429							{
430								modVal = "#" + val.substr(3) + val.substr(1,2);
431							}
432							else if (val == "TRANSPARENT")
433							{
434								modVal = "none";
435							}
436						break;
437						case "shape":
438//							console.log(val.toLowerCase());
439							modVal = mxGraphMlShapesMap[val.toLowerCase()];
440						break;
441						case "bpmnOutline":
442//							console.log(val.toLowerCase());
443							modVal = mxGraphMlShapesMap.bpmnOutline[val.toLowerCase()];
444						break;
445						case "bpmnSymbol":
446//							console.log(val.toLowerCase());
447							modVal = mxGraphMlShapesMap.bpmnSymbol[val.toLowerCase()];
448						break;
449						case "bool":
450							modVal = val == "true"? "1" : "0";
451						break;
452						case "scale":
453							try {
454								modVal = parseFloat(val) * mappingObj.scale;
455							} catch(e) {
456								//nothing!
457							}
458						break;
459						case "arrow":
460							modVal = mxGraphMlArrowsMap[val];
461						break;
462					}
463					if (modVal != null)
464						map[mappingObj.key] = modVal;
465				}
466				else
467				{
468					mappingObj(val, map);
469				}
470			}
471			else if (val instanceof Array)
472			{
473				this.mapArray(val, mappingObj, map);
474			}
475			else if (val.name != null && val.value != null) //this is the case when a single y:Property is used
476			{
477				this.mapArray([val], mappingObj, map);
478			}
479			else
480			{
481				this.mapObject(val, mappingObj, map);
482			}
483		}
484	}
485};
486
487mxGraphMlCodec.prototype.createMxGraph = function ()
488{
489    var graph = new mxGraph();
490//    graph.setExtendParents(false);
491//    graph.setExtendParentsOnAdd(false);
492//    graph.setConstrainChildren(false);
493//    graph.setHtmlLabels(true);
494//    graph.getModel().maintainEdgeParent = false;
495    return graph;
496}
497
498mxGraphMlCodec.prototype.importGraph = function (pageElement, graph, parent)
499{
500	var nodes = this.getDirectChildNamedElements(pageElement, mxGraphMlConstants.NODE);
501
502	var p = parent;
503	var dx = 0, dy = 0;
504	while (p && p.geometry)
505	{
506		dx += p.geometry.x;
507		dy += p.geometry.y;
508
509		p = p.parent;
510	}
511
512	for (var i = 0; i < nodes.length; i++)
513	{
514		this.importNode(nodes[i], graph, parent, dx, dy);
515	}
516
517	this.edges.push({
518		edges: this.getDirectChildNamedElements(pageElement, mxGraphMlConstants.EDGE),
519		parent: parent,
520		dx: dx,
521		dy: dy
522	});
523};
524
525//FIXME port 0.5, 0.5 push the edge to the other side (bpmn example)
526mxGraphMlCodec.prototype.importPort = function (portElement, portsMap)
527{
528	var name = portElement.getAttribute(mxGraphMlConstants.PORT_NAME);
529	var portObj = {};
530
531	var data = this.getDirectChildNamedElements(portElement, mxGraphMlConstants.DATA);
532
533	for (var i = 0; i < data.length; i++)
534	{
535		var d = data[i];
536		var key = d.getAttribute(mxGraphMlConstants.KEY);
537
538		var dataObj = this.dataElem2Obj(d);
539//		console.log(dataObj);
540		if (dataObj.key == this.portsKeys[mxGraphMlConstants.PORT_LOCATION_PARAMETER].key)
541		{
542			this.mapObject(dataObj, {
543				"y:FreeNodePortLocationModelParameter.Ratio": function(val, map)
544				{
545					var parts = val.split(',');
546					map["pos"] = {x: parts[0], y: parts[1]};
547				}
548			}, portObj);
549		}
550		/*
551		else if (dataObj.key == this.portsKeys[mxGraphMlConstants.PORT_STYLE].key)
552		{
553
554		}
555		else if (dataObj.key == this.portsKeys[mxGraphMlConstants.PORT_VIEW_STATE].key)
556		{
557
558		}*/
559	}
560
561	portsMap[name] = portObj;
562};
563
564mxGraphMlCodec.prototype.styleMap2Str = function (styleMap)
565{
566	var semi = "";
567	var str = "";
568
569	for (var key in styleMap)
570	{
571		str += semi + key + "=" + styleMap[key];
572		semi = ";";
573	}
574
575	return str;
576};
577
578mxGraphMlCodec.prototype.importNode = function (nodeElement, graph, parent, dx, dy)
579{
580	var data = this.getDirectChildNamedElements(nodeElement, mxGraphMlConstants.DATA);
581	var v;
582	var id = nodeElement.getAttribute(mxGraphMlConstants.ID);
583
584	var node = new mxCell();
585	node.vertex = true;
586	node.geometry = new mxGeometry(0,0,30,30); //some node has no geometry, this is the default
587
588	graph.addCell(node, parent);
589
590	var style = {graphMlID: id};
591	var mlStyleObj = null;
592	var mlTemplate = null;
593	var mlUserTags = null;
594	var lblObj = null;
595	var lbls = null;
596
597	for (var i = 0; i < data.length; i++)
598	{
599		var d = data[i];
600		var dataObj = this.dataElem2Obj(d);
601
602		if (dataObj.key)
603		{
604			if (dataObj.key == this.nodesKeys[mxGraphMlConstants.NODE_GEOMETRY].key)
605			{
606				this.addNodeGeo(node, dataObj, dx, dy);
607			}
608			else if (dataObj.key == this.nodesKeys[mxGraphMlConstants.USER_TAGS].key)
609			{
610				mlUserTags = dataObj;
611			}
612			else if (dataObj.key == this.nodesKeys[mxGraphMlConstants.NODE_STYLE].key)
613			{
614	//			console.log(JSON.stringify(dataObj));
615				mlStyleObj = dataObj;
616				if (dataObj["yjs:StringTemplateNodeStyle"])
617				{
618					mlTemplate = dataObj["yjs:StringTemplateNodeStyle"]["#text"];
619				}
620				else
621				{
622					this.addNodeStyle(node, dataObj, style);
623				}
624			}
625			else if (dataObj.key == this.nodesKeys[mxGraphMlConstants.NODE_LABELS].key)
626			{
627				lblObj = dataObj;
628			}
629			else if (dataObj.key == this.nodesKeys[mxGraphMlConstants.NODE_GRAPHICS].key)
630			{
631				var shape = null, key = null;
632				for (var key in dataObj)
633				{
634					if (key == "key" || key == "#text") continue;
635
636					//Special case when a node has multiple graphics
637					//TODO support the open/closed states
638					if (key == "y:ProxyAutoBoundsNode")
639					{
640						var realizers = dataObj[key]["y:Realizers"];
641						if (realizers)
642						{
643							for (var key2 in realizers)
644							{
645								if (key2 == "active" || key2 == "#text") continue;
646
647								shape = realizers[key2][realizers["active"]];
648								dataObj = {};
649								dataObj[key2] = shape;
650								break;
651							}
652						}
653					}
654					else
655					{
656						shape = dataObj[key];
657					}
658					break;
659				}
660				if (shape)
661				{
662					if (shape[mxGraphMlConstants.GEOMETRY])
663					{
664						this.addNodeGeo(node, shape[mxGraphMlConstants.GEOMETRY], dx, dy);
665					}
666
667					if (shape[mxGraphMlConstants.NODE_LABEL])
668					{
669						lblObj = shape[mxGraphMlConstants.NODE_LABEL];
670					}
671				}
672				mlStyleObj = dataObj;
673				this.addNodeStyle(node, dataObj, style);
674			}
675		}
676	}
677
678	var ports = this.getDirectChildNamedElements(nodeElement, mxGraphMlConstants.PORT);
679	var portsMap = {};
680
681	for (var i = 0; i < ports.length; i++)
682	{
683		this.importPort(ports[i], portsMap);
684	}
685
686	if (mlTemplate)
687	{
688		this.handleTemplates(mlTemplate, mlUserTags, node, style);
689	}
690
691	this.handleFixedRatio(node, style);
692
693	//handle special compound shapes
694	this.handleCompoundShape(node, style, mlStyleObj, lbls);
695
696	//fix for stroke size of zero
697	if (style["strokeWidth"] == 0)
698	{
699		style["strokeColor"] = "none";
700	}
701
702	node.style = this.styleMap2Str(style);
703
704	var subGraphs = this.getDirectChildNamedElements(nodeElement, mxGraphMlConstants.GRAPH);
705
706	for (var i = 0; i < subGraphs.length; i++)
707	{
708		this.importGraph(subGraphs[i], graph, node, portsMap);
709	}
710
711	//handle labels after node geometry is determined. It is also the last such that labels are on top
712	if (lblObj)
713		lbls = this.addLabels(node, lblObj, style, graph);
714
715	this.nodesMap[id] = {node: node, ports: portsMap};
716};
717
718mxGraphMlCodec.prototype.addNodeStyle = function (node, dataObj, style)
719{
720	//TODO move these static mapping objects outside such that they are defined once only
721	var dashStyleFn = function(val, map)
722	{
723		if (val == "line") return;
724
725		map["dashed"] = 1;
726		//map["fixDash"] = 1;
727		var pattern = null;
728		switch(val)
729		{
730			case "DashDot":
731				pattern = "3 1 1 1";
732			break;
733			case "Dot":
734				pattern = "1 1";
735			break;
736			case "DashDotDot":
737				pattern = "3 1 1 1 1 1";
738			break;
739			case "Dash":
740				pattern = "3 1";
741			break;
742			case "dotted":
743				pattern = "1 3";
744			break;
745			case "dashed":
746				pattern = "5 2";
747			break;
748			default:
749				pattern = val.replace(/0/g, '1');
750		}
751
752		if (pattern)
753		{
754			//Some patterns in graphML has only one number
755			if (pattern.indexOf(" ") < 0)
756			{
757				pattern = pattern + " " + pattern;
758			}
759			map["dashPattern"] = pattern;
760		}
761	};
762
763	var styleCommonMap =
764	{
765		"shape": {key: "shape", mod: "shape"},
766		"y:Shape.type": {key: "shape", mod: "shape"},
767		"configuration": {key: "shape", mod: "shape"},
768		"type": {key: "shape", mod: "shape"},
769		"assetName": {key: "shape", mod: "shape"},
770		"activityType": {key: "shape", mod: "shape"},
771		"fill": {key: "fillColor", mod: "color"},
772		"fill.yjs:SolidColorFill.color": {key: "fillColor", mod: "color"},
773		"fill.yjs:SolidColorFill.color.yjs:Color.value": {key: "fillColor", mod: "color"},
774		"y:Fill": {
775			"color": {key: "fillColor", mod: "color"},
776			//"color2": {key: "gradientColor", mod: "color"}, //??
777			"transparent": function(val, map)
778			{
779				if (val == "true")
780				{
781					map["fillColor"] = "none";
782				}
783			}
784		},
785		"y:BorderStyle": {
786			"color": {key: "strokeColor", mod: "color"},
787			"width": "strokeWidth",
788			"hasColor":  function(val, map)
789			{
790				if (val == "false")
791				{
792					map["strokeColor"] = "none";
793				}
794			},
795			"type": dashStyleFn
796			//"raised": ??
797		},
798		"stroke": {key: "strokeColor", mod: "color"},
799		"stroke.yjs:Stroke":
800		{
801			"dashStyle": dashStyleFn,
802			"dashStyle.yjs:DashStyle.dashes": dashStyleFn,
803			"fill": {key: "strokeColor", mod: "color"},
804			"fill.yjs:SolidColorFill.color": {key: "strokeColor", mod: "color"},
805			//"lineCap": "", //??
806			"thickness.sys:Double": "strokeWidth",
807			"thickness": "strokeWidth"
808		}
809	};
810
811	var assetNodesStyle = mxUtils.clone(styleCommonMap);
812	assetNodesStyle["defaults"] = {
813		"fillColor": "#CCCCCC",
814		"strokeColor": "#6881B3"
815	};
816
817	var bpmnActivityStyle = mxUtils.clone(styleCommonMap);
818	bpmnActivityStyle["defaults"] = {
819		"shape": "ext;rounded=1",
820		"fillColor": "#FFFFFF",
821		"strokeColor": "#000090"
822	};
823
824	var bpmnGatewayStyle = mxUtils.clone(styleCommonMap);
825	bpmnGatewayStyle["defaults"] = {
826		"shape": "rhombus;fillColor=#FFFFFF;strokeColor=#FFCD28"
827	};
828
829	var bpmnConversationStyle = mxUtils.clone(styleCommonMap);
830	bpmnConversationStyle["defaults"] = {
831		"shape": "hexagon",
832		"strokeColor": "#007000"
833	};
834
835	var bpmnEventStyle = mxUtils.clone(styleCommonMap);
836	bpmnEventStyle["defaults"] = {
837		"shape": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=general",
838		"outline": "standard"
839	};
840	bpmnEventStyle["characteristic"] = {key: "outline", mod: "bpmnOutline"};
841
842	var bpmnDataObjectStyle = mxUtils.clone(styleCommonMap);
843	bpmnDataObjectStyle["defaults"] = {
844		"shape": "js:bpmnDataObject"
845	};
846
847	var bpmnDataStoreStyle = mxUtils.clone(styleCommonMap);
848	bpmnDataStoreStyle["defaults"] = {
849		"shape": "datastore"
850	};
851
852	var bpmnGroupNodeStyle = mxUtils.clone(styleCommonMap);
853	bpmnGroupNodeStyle["defaults"] = {
854		"shape": "swimlane;swimlaneLine=0;startSize=20;dashed=1;dashPattern=3 1 1 1;collapsible=0;rounded=1"
855	};
856
857	var bpmnChoreographyNodeStyle = mxUtils.clone(styleCommonMap);
858	bpmnChoreographyNodeStyle["defaults"] = {
859		"shape": "js:BpmnChoreography"//"swimlane;childLayout=stackLayout;horizontal=1;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;startSize=20;rounded=1;collapsible=0"
860	};
861
862	//approximation to GraphML shapes TODO improve them
863	var bevelNodeStyle = mxUtils.clone(styleCommonMap);
864	bevelNodeStyle["defaults"] = {
865		"rounded": "1",
866		"glass": "1",
867		"strokeColor": "#FFFFFF"
868	};
869	bevelNodeStyle["inset"] = "strokeWidth";
870	bevelNodeStyle["radius"] = "arcSize";
871	bevelNodeStyle["drawShadow"] = {key:"shadow", mod:"bool"};
872	bevelNodeStyle["color"] = {key:"fillColor", mod:"color", addGradient: "north"};
873	bevelNodeStyle["color.yjs:Color.value"] = bevelNodeStyle["color"];
874
875	var shinyPlateNodeStyle = mxUtils.clone(styleCommonMap);
876	shinyPlateNodeStyle["defaults"] = {
877		"rounded": "1",
878		"arcSize": 10,
879		"glass": "1",
880		"shadow": "1",
881		"strokeColor": "none"
882		//,"rotation": -90 //TODO requires rotation!
883	};
884	shinyPlateNodeStyle["drawShadow"] = {key:"shadow", mod:"bool"};
885
886	var demoGroupStyle = mxUtils.clone(styleCommonMap);
887	demoGroupStyle["defaults"] = {
888		"shape": "swimlane",
889		"startSize": 20,
890		"strokeWidth": 4,
891		"spacingLeft": 10 //TODO can we change collapse icon to be in right side?
892	};
893	demoGroupStyle["isCollapsible"] = {key:"collapsible", mod:"bool"};
894	demoGroupStyle["borderColor"] = {key:"strokeColor", mod:"color"};
895	demoGroupStyle["folderFrontColor"] = {key:"fillColor", mod:"color"}; //TODO fillColor always match strokeColor!
896//			demoGroupStyle["folderBackColor"] = {key:"fillColor", mod:"color"}; //??
897
898	var collapsibleNodeStyle = mxUtils.clone(styleCommonMap);
899	collapsibleNodeStyle["defaults"] = {
900		"shape": "swimlane",
901		"startSize": 20,
902		"spacingLeft": 10 //TODO can we change collapse icon to be in right side?
903	};
904	collapsibleNodeStyle["yjs:PanelNodeStyle"] = {
905		"color": {key:"swimlaneFillColor", mod:"color"},
906		"color.yjs:Color.value": {key:"swimlaneFillColor", mod:"color"},
907		"labelInsetsColor": {key:"fillColor", mod:"color"},
908		"labelInsetsColor.yjs:Color.value": {key:"fillColor", mod:"color"}
909	};
910
911	var tableStyle = mxUtils.clone(styleCommonMap);
912	tableStyle["defaults"] = {
913		"shape": "js:table"
914	};
915
916	var imageNodeStyle = mxUtils.clone(styleCommonMap);
917	imageNodeStyle["defaults"] = {
918		"shape": "image"
919	};
920
921	imageNodeStyle["image"] = function(val, map)
922	{
923		map["image"] = val;
924	};
925
926	var svgNodeStyle = mxUtils.clone(styleCommonMap);
927	svgNodeStyle["defaults"] = {
928		"shape": "image"
929	};
930//	svgNodeStyle["y:SVGNodeProperties"] = {
931//		"usingVisualBounds": ""//??
932//	};
933//	y:SVGModel.svgBoundsPolicy ??
934	svgNodeStyle["y:SVGModel.y:SVGContent.y:Resource.#text"] = function(val, map)
935	{
936		map["image"] = "data:image/svg+xml," + ((window.btoa) ? btoa(val) : Base64.encode(val));
937	};
938
939	var groupNodeStyle = mxUtils.clone(styleCommonMap);
940	groupNodeStyle["defaults"] = {
941		"shape": "swimlane",
942		"startSize": 20
943	};
944
945	groupNodeStyle["y:Shape.type"] = function(val, map)
946	{
947		if (val == "roundrectangle")
948		{
949			map['rounded'] = 1;
950			map['arcSize'] = 5;
951		}
952	};
953
954	var tableNodeStyle = mxUtils.clone(styleCommonMap);
955	tableNodeStyle["defaults"] = {
956		"shape": "js:table2"
957	};
958
959	var genericNodeStyle = mxUtils.clone(styleCommonMap);
960	genericNodeStyle["defaults"] = {
961		"gradientDirection": "east"
962	};
963	genericNodeStyle["y:Fill"]["color2"] = {key: "gradientColor", mod: "color"};
964	genericNodeStyle["y:StyleProperties.y:Property"] = {
965		"com.yworks.bpmn.characteristic": {key: "outline", mod: "bpmnOutline"},
966		//TODO support colors for the icon itself other than the remaining shape!
967//		"com.yworks.bpmn.icon.line.color": "",
968		"com.yworks.bpmn.icon.fill": {key:"gradientColor", mod:"color"},
969		"com.yworks.bpmn.icon.fill2": {key:"fillColor", mod:"color"},
970		"com.yworks.bpmn.type": {key: "symbol", mod: "bpmnSymbol"},
971		"y.view.ShadowNodePainter.SHADOW_PAINTING": {key: "shadow", mod: "bool"},
972		"doubleBorder": {key: "double", mod: "bool"},
973		"com.yworks.sbgn.style.radius": {key: "arcSize", mod: "scale", scale: 2},
974		"com.yworks.sbgn.style.inverse": {key: "flipV", mod: "bool"}
975	};
976//	console.log(dataObj);
977	this.mapObject(dataObj, {
978		"yjs:ShapeNodeStyle": styleCommonMap,
979		"demostyle:FlowchartNodeStyle": styleCommonMap,
980		"demostyle:AssetNodeStyle": assetNodesStyle,
981		"bpmn:ActivityNodeStyle": bpmnActivityStyle,
982		"bpmn:GatewayNodeStyle": bpmnGatewayStyle,
983		"bpmn:ConversationNodeStyle": bpmnConversationStyle,
984		"bpmn:EventNodeStyle": bpmnEventStyle,
985		"bpmn:DataObjectNodeStyle": bpmnDataObjectStyle,
986		"bpmn:DataStoreNodeStyle": bpmnDataStoreStyle,
987		"bpmn:GroupNodeStyle": bpmnGroupNodeStyle,
988		"bpmn:ChoreographyNodeStyle": bpmnChoreographyNodeStyle,
989		"yjs:BevelNodeStyle": bevelNodeStyle,
990		"yjs:ShinyPlateNodeStyle": shinyPlateNodeStyle,
991		"demostyle:DemoGroupStyle": demoGroupStyle,
992		"yjs:CollapsibleNodeStyleDecorator": collapsibleNodeStyle,
993		"bpmn:PoolNodeStyle": tableStyle,
994		"yjs:TableNodeStyle": tableStyle,
995		"demotablestyle:DemoTableStyle": tableStyle,
996		"yjs:ImageNodeStyle": imageNodeStyle,
997		//desktop
998		"y:ShapeNode": styleCommonMap,
999		"y:GenericNode": genericNodeStyle,
1000		"y:GenericGroupNode": genericNodeStyle,
1001		"y:TableNode": tableNodeStyle,
1002		"y:SVGNode": svgNodeStyle,
1003		"y:GroupNode": groupNodeStyle
1004	}, style);
1005};
1006
1007mxGraphMlCodec.prototype.handleTemplates = function (template, userTags, node, styleMap)
1008{
1009	if (template)
1010	{
1011		var w = node.geometry.width;
1012		var h = node.geometry.height;
1013		var header = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 '+ w + ' ' + h +'"><g>';
1014		var footer = '</g></svg>';
1015
1016		//TODO optimize this! probably only the text before defs has bindings
1017		var matches = null;
1018		var bindingPairs = [];
1019		//find template bindings
1020		var tempBindRegEx = /\{TemplateBinding\s+([^}]+)\}/g;
1021
1022		while ((matches = tempBindRegEx.exec(template)) != null)
1023		{
1024	        var replacement = "";
1025	        switch (matches[1])
1026	        {
1027	        	case "width":
1028	        		replacement = w;
1029	        	break;
1030	        	case "height":
1031	        		replacement = h;
1032	    		break;
1033	        }
1034
1035	        bindingPairs.push({match: matches[0], repl: replacement});
1036		}
1037
1038		if (userTags && userTags["y:Json"])
1039		{
1040			var json = JSON.parse(userTags["y:Json"]["#text"]);
1041			//find user tags bindings
1042			var userTagBindRegEx = /\{Binding\s+([^}]+)\}/g;
1043
1044			while ((matches = userTagBindRegEx.exec(template)) != null)
1045			{
1046		        var parts = matches[1].split(',');
1047		        var val = json[parts[0]];
1048
1049		        if (val)
1050	        	{
1051		        	if (parts.length > 1)
1052	        		{
1053		        		if (parts[1].indexOf('Converter='))
1054	        			{
1055		        			var func = mxGraphMlConverters[parts[1].substr(11)]; //11 is the length of Converter=
1056
1057		        			if (func)
1058	        				{
1059				        		var args = [val];
1060
1061				        		if (parts[2])
1062				        		{
1063				        			args.push(parts[2].substr(11)); //11 is the length of Parameter=
1064				        		}
1065
1066		        				val = func.apply(null, args)
1067	        				}
1068	        			}
1069	        		}
1070
1071		        	bindingPairs.push({match: matches[0], repl: mxUtils.htmlEntities(val)});
1072	        	}
1073			}
1074		}
1075
1076		for (var i = 0; i < bindingPairs.length; i++)
1077		{
1078			template = template.replace(bindingPairs[i].match, bindingPairs[i].repl);
1079		}
1080
1081		bindingPairs = [];
1082		//Fix text elements (TODO can it be merged with the previous step?)
1083		var txtRegEx = /\<text.+data-content="([^"]+).+\<\/text\>/g;
1084		while ((matches = txtRegEx.exec(template)) != null)
1085		{
1086			var val = matches[0].substr(0, matches[0].length - 7) + matches[1] + "</text>"; //7 is the length of </text>
1087			bindingPairs.push({match: matches[0], repl: val});
1088		}
1089
1090		for (var i = 0; i < bindingPairs.length; i++)
1091		{
1092			template = template.replace(bindingPairs[i].match, bindingPairs[i].repl);
1093		}
1094
1095		var svg = header + template + footer;
1096		styleMap["shape"] = "image";
1097		styleMap["image"] = "data:image/svg+xml," + ((window.btoa) ? btoa(svg) : Base64.encode(svg));
1098	}
1099};
1100
1101mxGraphMlCodec.prototype.handleCompoundShape = function (node, styleMap, mlStyleObj, lbls)
1102{
1103	var shape = styleMap["shape"];
1104
1105	if (shape && shape.indexOf("js:") == 0)
1106	{
1107		switch(shape)
1108		{
1109			case "js:bpmnArtifactShadow":
1110				styleMap["shadow"] = "1";
1111			case "js:bpmnArtifact":
1112				styleMap["shape"] = styleMap["symbol"];
1113				delete styleMap["fillColor"];
1114				delete styleMap["strokeColor"];
1115				delete styleMap["gradientColor"];
1116				this.handleCompoundShape(node, styleMap, mlStyleObj, lbls)
1117			break;
1118			case "js:bpmnDataObjectShadow":
1119			case "js:bpmnDataObject":
1120				styleMap["shape"] = "note;size=16";
1121//				console.log(mlStyleObj);
1122				mlStyleObj = mlStyleObj["bpmn:DataObjectNodeStyle"] || mlStyleObj["y:GenericNode"] || mlStyleObj["y:GenericGroupNode"];
1123				var tmpMap = {};
1124
1125				this.mapObject(mlStyleObj, {
1126					"y:StyleProperties.y:Property": {
1127						"com.yworks.bpmn.dataObjectType": "dataObjectType",
1128						"com.yworks.bpmn.marker1": "marker1"
1129					}
1130				}, tmpMap);
1131
1132				if (mlStyleObj["collection"] == "true" || tmpMap["marker1"] == "bpmn_marker_parallel")
1133				{
1134					var cell2 = new mxCell('', new mxGeometry(0.5, 1, 10, 10), 'html=1;whiteSpace=wrap;shape=parallelMarker;');
1135					cell2.vertex = true;
1136					cell2.geometry.relative = true;
1137					cell2.geometry.offset = new mxPoint(-5, -10);
1138					node.insert(cell2);
1139				}
1140				if (mlStyleObj["type"] == "INPUT" || tmpMap["dataObjectType"] == "data_object_type_input")
1141				{
1142					var cell1 = new mxCell('', new mxGeometry(0, 0, 10, 10), 'html=1;shape=singleArrow;arrowWidth=0.4;arrowSize=0.4;');
1143					cell1.vertex = true;
1144					cell1.geometry.relative = true;
1145					cell1.geometry.offset = new mxPoint(2, 2);
1146					node.insert(cell1);
1147				}
1148				else if (mlStyleObj["type"] == "OUTPUT" || tmpMap["dataObjectType"] == "data_object_type_output")
1149				{
1150					var cell1 = new mxCell('', new mxGeometry(0, 0, 10, 10), 'html=1;shape=singleArrow;arrowWidth=0.4;arrowSize=0.4;fillColor=#000000;');
1151					cell1.vertex = true;
1152					cell1.geometry.relative = true;
1153					cell1.geometry.offset = new mxPoint(2, 2);
1154					node.insert(cell1);
1155				}
1156			break;
1157			case "js:BpmnChoreography":
1158				this.mapObject(mlStyleObj, {
1159					"defaults": {
1160						"shape": "swimlane;collapsible=0;rounded=1",
1161						"startSize": "20",
1162						"strokeColor": "#006000",
1163						"fillColor": "#CCCCCC"
1164					}
1165				}, styleMap);
1166
1167				//TODO the shape should be clipped by parent borders. It should also be resized relative to its parent
1168				var pGeo = node.geometry;
1169				var cell1 = new mxCell('', new mxGeometry(0, pGeo.height - 20, pGeo.width, 20), 'strokeColor=#006000;fillColor=#777777;rounded=1');
1170				cell1.vertex = true;
1171				node.insert(cell1);
1172
1173				//TODO handle labels accurately
1174				if (lbls && lbls.lblTxts)
1175				{
1176//					console.log(lbls);
1177					node.value = lbls.lblTxts[0];
1178					cell1.value = lbls.lblTxts[1];
1179				}
1180			break;
1181			case "js:bpmnActivityShadow":
1182			case "js:bpmnActivity":
1183				styleMap["shape"] = "ext;rounded=1";
1184				var tmpMap = {};
1185				mlStyleObj = mlStyleObj["y:GenericNode"] || mlStyleObj["y:GenericGroupNode"];
1186
1187				this.mapObject(mlStyleObj, {
1188					"y:StyleProperties.y:Property": {
1189						"com.yworks.bpmn.taskType": "taskType",
1190						"com.yworks.bpmn.activityType": "activityType",
1191						"com.yworks.bpmn.marker1": "marker1",
1192						"com.yworks.bpmn.marker2": "marker2",
1193						"com.yworks.bpmn.marker3": "marker3",
1194						"com.yworks.bpmn.marker4": "marker4"
1195					}
1196				}, tmpMap);
1197
1198				switch(tmpMap["activityType"])
1199				{
1200					case "activity_type_transaction":
1201						styleMap["double"] = "1";
1202					break;
1203				}
1204
1205				switch(tmpMap["taskType"])
1206				{
1207					case "task_type_send":
1208						var item1 = new mxCell('', new mxGeometry(0, 0, 19, 12), 'shape=message;fillColor=#000000;strokeColor=#FFFFFF;');
1209						item1.geometry.offset = new mxPoint(4, 7);
1210						break;
1211					case "task_type_receive":
1212						var item1 = new mxCell('', new mxGeometry(0, 0, 19, 12), 'shape=message;');
1213						item1.geometry.offset = new mxPoint(4, 7);
1214						break;
1215					case "task_type_user":
1216						var item1 = new mxCell('', new mxGeometry(0, 0, 15, 15), 'shape=mxgraph.bpmn.user_task;');
1217						item1.geometry.offset = new mxPoint(4, 5);
1218						break;
1219					case "task_type_manual":
1220						var item1 = new mxCell('', new mxGeometry(0, 0, 15, 10), 'shape=mxgraph.bpmn.manual_task;');
1221						item1.geometry.offset = new mxPoint(4, 7);
1222						break;
1223					case "task_type_business_rule":
1224						var item1 = new mxCell('', new mxGeometry(0, 0, 18, 13), 'shape=mxgraph.bpmn.business_rule_task;');
1225						item1.geometry.offset = new mxPoint(4, 7);
1226						break;
1227					case "task_type_service":
1228						var item1 = new mxCell('', new mxGeometry(0, 0, 15, 15), 'shape=mxgraph.bpmn.service_task;');
1229						item1.geometry.offset = new mxPoint(4, 5);
1230						break;
1231					case "task_type_script":
1232						var item1 = new mxCell('', new mxGeometry(0, 0, 15, 15), 'shape=mxgraph.bpmn.script_task;');
1233						item1.geometry.offset = new mxPoint(4, 5);
1234						break;
1235				}
1236
1237				if (item1)
1238				{
1239					item1.vertex = true;
1240					item1.geometry.relative = true;
1241					node.insert(item1);
1242					item1 = null;
1243				}
1244
1245				var numIcons = 0;
1246
1247				for (var i = 1; i <= 4; i++)
1248				{
1249					if (tmpMap["marker" + i])
1250						numIcons++;
1251				}
1252
1253				var iconX = -7.5 * numIcons - 2 * (numIcons - 1);
1254
1255				for (var i = 1; i <= numIcons; i++)
1256				{
1257					switch(tmpMap["marker" + i])
1258					{
1259						case "bpmn_marker_closed":
1260							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 15), 'shape=plus;part=1;');
1261							item1.geometry.offset = new mxPoint(iconX, -20);
1262							break;
1263						case "bpmn_marker_open":
1264							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 15), 'shape=rect;part=1;');
1265							item1.geometry.offset = new mxPoint(iconX, -20);
1266							var item2 = new mxCell('', new mxGeometry(0.5, 0.5, 8, 1), 'shape=rect;part=1;');
1267							item2.geometry.offset = new mxPoint(-4, -1);
1268							item2.geometry.relative = true;
1269							item2.vertex = true;
1270							item1.insert(item2);
1271							break;
1272						case "bpmn_marker_loop":
1273							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 15), 'shape=mxgraph.bpmn.loop;part=1;');
1274							item1.geometry.offset = new mxPoint(iconX, -20);
1275							break;
1276						case "bpmn_marker_parallel":
1277							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 15), 'shape=parallelMarker;part=1;');
1278							item1.geometry.offset = new mxPoint(iconX, -20);
1279							break;
1280						case "bpmn_marker_sequential":
1281							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 15), 'shape=parallelMarker;direction=south;part=1;');
1282							item1.geometry.offset = new mxPoint(iconX, -20);
1283							break;
1284						case "bpmn_marker_ad_hoc":
1285							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 10), 'shape=mxgraph.bpmn.ad_hoc;strokeColor=none;flipH=1;part=1;fillColor=#000000');
1286							item1.geometry.offset = new mxPoint(iconX, -17);
1287							break;
1288						case "bpmn_marker_compensation":
1289							var item1 = new mxCell('', new mxGeometry(0.5, 1, 15, 11), 'shape=mxgraph.bpmn.compensation;part=1;');
1290							item1.geometry.offset = new mxPoint(iconX, -18);
1291							break;
1292					}
1293					item1.geometry.relative = true;
1294					item1.vertex = true;
1295					node.insert(item1);
1296					iconX += 20;
1297				}
1298			break;
1299			case "js:table":
1300				//TODO we need 2 passes to find the exact shift of columns/rows especially when there is rows inside rows
1301				//TODO Internal table strokes needs to match table strokeWidth and only be on one side
1302				//TODO code optimization
1303				styleMap["shape"] = "swimlane;collapsible=0;swimlaneLine=0";
1304				var tableObj = mlStyleObj["yjs:TableNodeStyle"] || mlStyleObj["demotablestyle:DemoTableStyle"];
1305
1306				if (!tableObj && mlStyleObj["bpmn:PoolNodeStyle"])
1307				{
1308					tableObj = mlStyleObj["bpmn:PoolNodeStyle"]["yjs:TableNodeStyle"];
1309				}
1310
1311//				console.log(tableObj);
1312
1313				this.mapObject(tableObj, {
1314					"backgroundStyle.demotablestyle:TableBackgroundStyle": {
1315						"insetFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "fillColor", mod: "color"},
1316						"tableBackgroundFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "swimlaneFillColor", mod: "color"},
1317						"tableBackgroundStroke.yjs:Stroke":{
1318							"fill": {key: "strokeColor", mod: "color"},
1319							"thickness": "strokeWidth"
1320						}
1321					},
1322					"backgroundStyle.yjs:ShapeNodeStyle.fill": {key: "fillColor", mod: "color"},
1323					"backgroundStyle.yjs:ShapeNodeStyle.fill.yjs:SolidColorFill.color": {key: "fillColor", mod: "color"}
1324				}, styleMap);
1325
1326				//Lane fill color is the same as the fill color
1327				styleMap["swimlaneFillColor"] = styleMap["fillColor"];
1328
1329				tableObj = tableObj["table"]["y:Table"];
1330
1331				var x = 0, y = 0, xShift = {x: 0}, yShift = 0;
1332				var insets = tableObj["Insets"];
1333
1334				if (insets)
1335				{
1336					insets = insets.split(',');
1337
1338					if (insets[0] != "0")
1339					{
1340						styleMap["startSize"] = insets[0];
1341						xShift.x = parseFloat(insets[0]);
1342						//x += xShift.x;
1343						styleMap["horizontal"] = "0";
1344					}
1345					else if (insets[1] != "0")
1346					{
1347						styleMap["startSize"] = insets[1];
1348						yShift = parseFloat(insets[1]);
1349						y += yShift;
1350					}
1351				}
1352				else
1353				{
1354					styleMap["startSize"] = "0";
1355				}
1356
1357				var defRowStyle = {};
1358
1359				var rowMapping = {
1360					"Insets": function(val, map)
1361					{
1362						map["startSize"] = val.split(',')[0];
1363					},
1364					"Style.bpmn:AlternatingLeafStripeStyle": {
1365						"evenLeafDescriptor.bpmn:StripeDescriptor": {
1366							"insetFill": {key: "evenFill", mod: "color"},
1367							"backgroundFill": {key: "evenLaneFill", mod: "color"}
1368						},
1369						"oddLeafDescriptor.bpmn:StripeDescriptor": {
1370							"insetFill": {key: "oddFill", mod: "color"},
1371							"backgroundFill": {key: "oddLaneFill", mod: "color"}
1372						}
1373						//parentDescriptor ??
1374						//TODO collect common types in a special mapping hash
1375					},
1376					"Style.yjs:NodeStyleStripeStyleAdapter":{
1377						"demotablestyle:DemoStripeStyle": {
1378							"stripeInsetFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "fillColor", mod: "color"},
1379							"tableLineFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "strokeColor", mod: "color"}
1380						},
1381						"yjs:ShapeNodeStyle": {
1382							"fill": {key: "swimlaneFillColor", mod: "color"}
1383						}
1384					},
1385					"Size": "height"
1386				};
1387				this.mapObject(tableObj["RowDefaults"], {
1388					"defaults": {
1389						"shape": "swimlane;collapsible=0;horizontal=0",
1390						"startSize": "0"
1391					},
1392					"y:StripeDefaults": rowMapping
1393				}, defRowStyle);
1394
1395				var defColStyle = {};
1396
1397				var colMapping = {
1398					"Insets": function(val, map)
1399					{
1400						map["startSize"] = val.split(',')[1];
1401					},
1402					"Style.bpmn:AlternatingLeafStripeStyle": {
1403						"evenLeafDescriptor.bpmn:StripeDescriptor": {
1404							"insetFill": {key: "evenFill", mod: "color"},
1405							"backgroundFill": {key: "evenLaneFill", mod: "color"}
1406						},
1407						"oddLeafDescriptor.bpmn:StripeDescriptor": {
1408							"insetFill": {key: "oddFill", mod: "color"},
1409							"backgroundFill": {key: "oddLaneFill", mod: "color"}
1410						}
1411						//parentDescriptor ??
1412						//TODO collect common types in a special mapping hash
1413					},
1414					"Style.yjs:NodeStyleStripeStyleAdapter":{
1415						"demotablestyle:DemoStripeStyle": {
1416							"stripeInsetFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "fillColor", mod: "color"},
1417							"tableLineFill.yjs:SolidColorFill.color.yjs:Color.value": {key: "strokeColor", mod: "color"}
1418						},
1419						"yjs:ShapeNodeStyle": {
1420							"fill": {key: "swimlaneFillColor", mod: "color"}
1421						}
1422					},
1423					"Size": "width"
1424				};
1425
1426				this.mapObject(tableObj["ColumnDefaults"], {
1427					"defaults": {
1428						"shape": "swimlane;collapsible=0",
1429						"startSize": "0",
1430						"fillColor": "none"
1431					},
1432					"y:StripeDefaults": colMapping
1433				}, defColStyle);
1434
1435				var pGeo = node.geometry;
1436
1437				var rows = tableObj["Rows"]["y:Row"];
1438				y += parseFloat(defColStyle["startSize"]);
1439
1440				var maxX = xShift.x;
1441				var initX = xShift.x;
1442				xShift.lx = xShift.x;
1443
1444				//TODO We need two passes to determine the header size!
1445				if (rows)
1446				{
1447					if (!(rows instanceof Array))
1448						rows = [rows];
1449
1450					for (var i = 0; i < rows.length; i++)
1451					{
1452						xShift.x = initX;
1453						xShift.lx = initX;
1454						y = this.addRow(rows[i], node, (i & 1), y, xShift, rowMapping, defRowStyle);
1455						maxX = Math.max(xShift.x, maxX);
1456					}
1457				}
1458
1459				var columns = tableObj["Columns"]["y:Column"];
1460				x = maxX;//parseFloat(defRowStyle["startSize"]);
1461
1462				if (columns)
1463				{
1464					if (!(columns instanceof Array))
1465						columns = [columns];
1466
1467					for (var i = 0; i < columns.length; i++)
1468					{
1469						x = this.addColumn(columns[i], node, (i & 1), x, yShift, colMapping, defColStyle);
1470					}
1471				}
1472
1473			break;
1474			case "js:table2":
1475				styleMap["shape"] = "swimlane;collapsible=0;swimlaneLine=0";
1476//				console.log(mlStyleObj);
1477				var tmpMap = {};
1478				this.mapObject(mlStyleObj, {
1479					"y:TableNode": {
1480						"y:StyleProperties.y:Property": {
1481							"yed.table.section.color": {key: "secColor", mod: "color"},
1482							"yed.table.header.height": "headerH",
1483							"yed.table.header.color.main": {key: "headerColor", mod: "color"},
1484							"yed.table.header.color.alternating": {key: "headerColorAlt", mod: "color"},
1485							"yed.table.lane.color.main": {key: "laneColor", mod: "color"},
1486							"yed.table.lane.color.alternating": {key: "laneColorAlt", mod: "color"},
1487							"yed.table.lane.style": "laneStyle",
1488							"com.yworks.bpmn.type": "isHorz",
1489							"POOL_LANE_COLOR_ALTERNATING": {key: "laneColorAlt", mod: "color"},
1490							"POOL_LANE_COLOR_MAIN": {key: "laneColor", mod: "color"},
1491							"POOL_LANE_STYLE": "laneStyle",
1492							"POOL_HEADER_COLOR_MAIN": {key: "headerColor", mod: "color"},
1493							"POOL_HEADER_COLOR_ALTERNATING": {key: "headerColorAlt", mod: "color"},
1494							"POOL_TABLE_SECTION_COLOR": {key: "secColor", mod: "color"}
1495//							//Not Used!
1496//							"y.view.tabular.TableNodePainter.ALTERNATE_ROW_STYLE": {
1497//								"y:SimpleStyle": {
1498//									"fillColor": {key: "rowAltFillColor", mod: "color"},
1499//									"lineColor": {key: "rowAltLineColor", mod: "color"},
1500//									"lineType": "rowAltlineType",
1501//									"lineWidth": "rowAltlineWidth"
1502//								}
1503//							},
1504//							"y.view.tabular.TableNodePainter.ALTERNATE_COLUMN_STYLE": {
1505//								"y:SimpleStyle": {
1506//									"fillColor": {key: "colAltFillColor", mod: "color"},
1507//									"lineColor": {key: "colAltLineColor", mod: "color"},
1508//									"lineType": "colAltlineType",
1509//									"lineWidth": "colAltlineWidth"
1510//								}
1511//							}
1512						},
1513						"y:Table": {
1514							"y:DefaultColumnInsets.top": "colHHeight",
1515							"y:DefaultRowInsets.left": "rowHWidth",
1516							"y:Insets": {
1517								"top": "tblHHeight",
1518								"left": "tblHWidth"
1519							}
1520						}
1521					}
1522				}, tmpMap);
1523
1524				styleMap["swimlaneFillColor"] = styleMap["fillColor"];
1525
1526				var isHor = tmpMap["isHorz"] == "pool_type_lane_and_column"
1527					|| tmpMap["isHorz"] == "pool_type_empty"
1528					|| tmpMap["isHorz"] == "pool_type_lane";
1529
1530				var th = 0, tw = 0;
1531				if (isHor)
1532				{
1533					tw = parseFloat(tmpMap["tblHWidth"]);
1534				}
1535				else
1536				{
1537					th = parseFloat(tmpMap["tblHHeight"]);
1538				}
1539
1540				styleMap["startSize"] = th? th : tw;
1541				//Assumptions: There is always rows and cols in every table
1542				//Also all tables seems to be not rotated
1543				try
1544				{
1545					var rows = mlStyleObj["y:TableNode"]["y:Table"]["y:Rows"]["y:Row"];
1546					var cols = mlStyleObj["y:TableNode"]["y:Table"]["y:Columns"]["y:Column"];
1547
1548					var atts4Rows = tmpMap["laneStyle"] == "lane.style.rows" || tmpMap["laneStyle"] == "lane_style_rows";
1549
1550					if (!(rows instanceof Array))
1551						rows = [rows];
1552
1553					if (!(cols instanceof Array))
1554						cols = [cols];
1555
1556					var rowStartSize = parseFloat(tmpMap["rowHWidth"]);
1557					for (var i = 0; i < rows.length; i++)
1558					{
1559						if (rows[i]["y:Insets"])
1560							rowStartSize = Math.max(rowStartSize,
1561									parseFloat(rows[i]["y:Insets"]["left"]) + parseFloat(rows[i]["y:Insets"]["right"]));
1562					}
1563
1564					var colStartSize = parseFloat(tmpMap["colHHeight"]);
1565					for (var i = 0; i < cols.length; i++)
1566					{
1567						if (cols[i]["y:Insets"])
1568							colStartSize = Math.max(colStartSize,
1569									parseFloat(cols[i]["y:Insets"]["top"]) + parseFloat(cols[i]["y:Insets"]["bottom"]));
1570					}
1571
1572					if (atts4Rows)
1573					{
1574						this.addTbl2Rows(node, rows, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap);
1575						this.addTbl2Cols(node, cols, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap);
1576					}
1577					else
1578					{
1579						this.addTbl2Cols(node, cols, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap);
1580						this.addTbl2Rows(node, rows, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap);
1581					}
1582				}
1583				catch(e)
1584				{
1585					//nothing!
1586				}
1587			break;
1588			case "js:relationship_big_entity":
1589				styleMap['shape'] = "swimlane;startSize=30;rounded=1;arcSize=5;collapsible=0";
1590				var fill = mlStyleObj["y:GenericNode"]["y:Fill"];
1591
1592				if (fill)
1593				{
1594					styleMap['fillColor'] = fill["color2"];
1595					styleMap['swimlaneFillColor'] = fill["color"];
1596				}
1597			break;
1598			case "js:relationship_attribute":
1599				if (styleMap["double"] == "1")
1600				{
1601					styleMap['shape'] = "doubleEllipse";
1602				}
1603				else
1604				{
1605					styleMap['shape'] = "ellipse";
1606				}
1607			break;
1608		}
1609
1610		if (shape.indexOf("Shadow") > 0)
1611		{
1612			styleMap["shadow"] = "1";
1613		}
1614	}
1615};
1616
1617mxGraphMlCodec.prototype.addTbl2Rows = function(node, rows, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap)
1618{
1619	var y = th + colStartSize;
1620	var isBPMN = tmpMap["isHorz"] != null;
1621
1622	for (var i = 0; i < rows.length; i++)
1623	{
1624		var odd = i & 1;
1625		var cell = new mxCell();
1626		cell.vertex = true;
1627		var rowStyle = {
1628			"shape": "swimlane;collapsible=0;horizontal=0",
1629			"startSize": rowStartSize,
1630			"fillColor": tmpMap["secColor"] || "none",
1631			"swimlaneLine": (isBPMN? "0" : "1")
1632		};
1633
1634		if (parseFloat(rowStyle["startSize"]) == 0)
1635		{
1636			rowStyle["fillColor"] = "none";
1637			rowStyle["swimlaneLine"] = "0";
1638		}
1639
1640		if (atts4Rows)
1641		{
1642			var fillColor = odd? tmpMap["headerColorAlt"] : tmpMap["headerColor"];
1643			rowStyle["swimlaneFillColor"] = odd? tmpMap["laneColorAlt"] : tmpMap["laneColor"];
1644			rowStyle["fillColor"] = fillColor? fillColor : rowStyle["swimlaneFillColor"];
1645		}
1646
1647		var height = parseFloat(rows[i]["height"]);
1648		var dh = (isBPMN && i == 0)? colStartSize : 0 ;
1649		cell.geometry = new mxGeometry(tw, y - dh, node.geometry.width - tw, height + dh);
1650		y += height;
1651
1652//		if (lblObj)
1653//			this.addLabels(cell, lblObj, rowStyle)
1654
1655		cell.style = this.styleMap2Str(rowStyle);
1656		node.insert(cell);
1657	}
1658};
1659
1660mxGraphMlCodec.prototype.addTbl2Cols = function(node, cols, th, tw, rowStartSize, colStartSize, atts4Rows, tmpMap)
1661{
1662	var x = rowStartSize + tw;
1663	var isBPMN = tmpMap["isHorz"] != null;
1664
1665	for (var i = 0; i < cols.length; i++)
1666	{
1667		var odd = i & 1;
1668		var cell = new mxCell();
1669		cell.vertex = true;
1670		var colStyle = {
1671			"shape": "swimlane;collapsible=0",
1672			"startSize": colStartSize,
1673			"fillColor": tmpMap["secColor"] || "none",
1674			"swimlaneLine": (isBPMN? "0" : "1")
1675		};
1676
1677		if (parseFloat(colStyle["startSize"]) == 0)
1678		{
1679			colStyle["fillColor"] = "none";
1680		}
1681
1682		if (!atts4Rows)
1683		{
1684			var fillColor = odd? tmpMap["headerColorAlt"] : tmpMap["headerColor"];
1685			colStyle["swimlaneFillColor"] = odd? tmpMap["laneColorAlt"] : tmpMap["laneColor"];
1686			colStyle["fillColor"] = fillColor? fillColor : colStyle["swimlaneFillColor"];
1687		}
1688
1689		var width = parseFloat(cols[i]["width"]);
1690		var dw = (isBPMN && i == 0)? rowStartSize : 0 ;
1691		cell.geometry = new mxGeometry(x - dw, th, width + dw, node.geometry.height - th);
1692		x += width;
1693
1694//		if (lblObj)
1695//			this.addLabels(cell, lblObj, rowStyle)
1696
1697		cell.style = this.styleMap2Str(colStyle);
1698		node.insert(cell);
1699	}
1700};
1701
1702mxGraphMlCodec.prototype.addRow = function(row, parent, odd, y, xShift, rowMapping, defRowStyle)
1703{
1704	var cell = new mxCell();
1705	cell.vertex = true;
1706	var rowStyle = mxUtils.clone(defRowStyle);
1707	this.mapObject(row, rowMapping, rowStyle);
1708
1709	if (odd)
1710	{
1711		if (rowStyle["oddFill"])
1712			rowStyle["fillColor"] = rowStyle["oddFill"];
1713
1714		if (rowStyle["oddLaneFill"])
1715			rowStyle["swimlaneFillColor"] = rowStyle["oddLaneFill"];
1716	}
1717	else
1718	{
1719		if (rowStyle["evenFill"])
1720			rowStyle["fillColor"] = rowStyle["evenFill"];
1721
1722		if (rowStyle["evenLaneFill"])
1723			rowStyle["swimlaneFillColor"] = rowStyle["evenLaneFill"];
1724	}
1725
1726	var height = parseFloat(rowStyle["height"]);
1727	cell.geometry = new mxGeometry(xShift.lx, y, parent.geometry.width - xShift.lx, height);
1728
1729	var lblObj = row["Labels"];
1730
1731	if (lblObj)
1732		this.addLabels(cell, lblObj, rowStyle)
1733
1734	cell.style = this.styleMap2Str(rowStyle);
1735	parent.insert(cell);
1736
1737	var subRow = row["y:Row"];
1738
1739	xShift.lx = 0;
1740	if (rowStyle["startSize"])
1741	{
1742		xShift.lx = parseFloat(rowStyle["startSize"]);
1743		xShift.x += xShift.lx;
1744	}
1745
1746	var initX = xShift.x, maxX = xShift.x, initLx = xShift.lx;
1747	var subY = 0;
1748	if (subRow)
1749	{
1750		if (!(subRow instanceof Array))
1751			subRow = [subRow];
1752
1753		for (var i = 0; i < subRow.length; i++)
1754		{
1755			xShift.x = initX;
1756			xShift.lx = initLx;
1757			subY = this.addRow(subRow[i], cell, (i & 1), subY, xShift, rowMapping, defRowStyle);
1758			maxX = Math.max(xShift.x, maxX)
1759		}
1760	}
1761	xShift.x = maxX;
1762	height = Math.max(height, subY);
1763	cell.geometry.height = height;
1764	y += height;
1765
1766	return y;
1767}
1768
1769mxGraphMlCodec.prototype.addColumn = function(column, parent, odd, x, yShift, colMapping, defColStyle)
1770{
1771	var cell = new mxCell();
1772	cell.vertex = true;
1773	var colStyle = mxUtils.clone(defColStyle);
1774	this.mapObject(column, colMapping, colStyle);
1775
1776	if (odd)
1777	{
1778		if (colStyle["oddFill"])
1779			colStyle["fillColor"] = colStyle["oddFill"];
1780
1781		if (colStyle["oddLaneFill"])
1782			colStyle["swimlaneFillColor"] = colStyle["oddLaneFill"];
1783	}
1784	else
1785	{
1786		if (colStyle["evenFill"])
1787			colStyle["fillColor"] = colStyle["evenFill"];
1788
1789		if (colStyle["evenLaneFill"])
1790			colStyle["swimlaneFillColor"] = colStyle["evenLaneFill"];
1791	}
1792
1793	var width = parseFloat(colStyle["width"]);
1794	cell.geometry = new mxGeometry(x, yShift, width, parent.geometry.height - yShift);
1795
1796	var lblObj = column["Labels"];
1797
1798	if (lblObj)
1799		this.addLabels(cell, lblObj, colStyle)
1800
1801	cell.style = this.styleMap2Str(colStyle);
1802	parent.insert(cell);
1803
1804	var subCol = column["y:Column"];
1805
1806	var subX = 0;
1807	if (subCol)
1808	{
1809		if (!(subCol instanceof Array))
1810			subCol = [subCol];
1811
1812		for (var i = 0; i < subCol.length; i++)
1813		{
1814			subX = this.addColumn(subCol[i], cell, (i & 1), subX, yShift, colMapping, defColStyle);
1815		}
1816	}
1817	width = Math.max(width, subX);
1818	cell.geometry.width = width;
1819	x += width;
1820	return x;
1821}
1822
1823mxGraphMlCodec.prototype.handleFixedRatio = function (node, styleMap)
1824{
1825	var shape = styleMap["shape"];
1826	var geo = node.geometry;
1827
1828	if (shape && geo)
1829	{
1830		if (shape.indexOf(";aspect=fixed") > 0)
1831		{
1832
1833			var min = Math.min(geo.height, geo.width);
1834
1835			if (min == geo.height) //fix coordinates
1836			{
1837				geo.x += (geo.width - min) / 2;
1838			}
1839
1840			geo.height = min;
1841			geo.width = min;
1842		}
1843		else if (shape.indexOf(";rotation=90") > 0 || shape.indexOf(";rotation=-90") > 0 )
1844		{
1845			var h = geo.height;
1846			var w = geo.width;
1847			geo.height = w;
1848			geo.width = h;
1849			var diff = (h - w) / 2;
1850			geo.x -= diff;
1851			geo.y += diff;
1852		}
1853	}
1854};
1855
1856mxGraphMlCodec.prototype.addNodeGeo = function (node, geoObj, dx, dy)
1857{
1858	var geoRect = geoObj[mxGraphMlConstants.RECT];
1859
1860	var x = 0, y = 0, w = 30, h = 30; //some node has no geometry, this is the default
1861	if (geoRect)
1862	{
1863		x = geoRect[mxGraphMlConstants.X];
1864		y = geoRect[mxGraphMlConstants.Y];
1865		w = geoRect[mxGraphMlConstants.WIDTH];
1866		h = geoRect[mxGraphMlConstants.HEIGHT];
1867	}
1868	else
1869	{
1870		x = geoObj[mxGraphMlConstants.X_L] || x;
1871		y = geoObj[mxGraphMlConstants.Y_L] || y;
1872		w = geoObj[mxGraphMlConstants.WIDTH_L] || w;
1873		h = geoObj[mxGraphMlConstants.HEIGHT_L] || h;
1874	}
1875
1876	var geo = node.geometry;
1877	geo.x = parseFloat(x) - dx;
1878	geo.y = parseFloat(y) - dy;
1879	geo.width = parseFloat(w);
1880	geo.height = parseFloat(h);
1881};
1882
1883//TODO handle other ports cases
1884mxGraphMlCodec.prototype.importEdge = function (edgeElement, graph, parent, dx, dy)
1885{
1886	var data = this.getDirectChildNamedElements(edgeElement, mxGraphMlConstants.DATA);
1887	var e;
1888	var id = edgeElement.getAttribute(mxGraphMlConstants.ID);
1889	var srcId = edgeElement.getAttribute(mxGraphMlConstants.EDGE_SOURCE);
1890	var trgId = edgeElement.getAttribute(mxGraphMlConstants.EDGE_TARGET);
1891	var srcPortId = edgeElement.getAttribute(mxGraphMlConstants.EDGE_SOURCE_PORT);
1892	var trgPortId = edgeElement.getAttribute(mxGraphMlConstants.EDGE_TARGET_PORT);
1893
1894	var src = this.nodesMap[srcId];
1895	var trg = this.nodesMap[trgId];
1896
1897	var edge = graph.insertEdge(parent, null, "", src.node, trg.node, "graphMLId=" + id);
1898	var style = {graphMlID: id};
1899
1900	for (var i = 0; i < data.length; i++)
1901	{
1902		var d = data[i];
1903		var dataObj = this.dataElem2Obj(d);
1904		var desktopEdgeObj = dataObj["y:PolyLineEdge"] || dataObj["y:GenericEdge"] ||
1905							dataObj["y:ArcEdge"] || dataObj["y:BezierEdge"] ||
1906							dataObj["y:QuadCurveEdge"] || dataObj["y:SplineEdge"];
1907
1908		if (dataObj.key == this.edgesKeys[mxGraphMlConstants.EDGE_GEOMETRY].key)
1909		{
1910			this.addEdgeGeo(edge, dataObj, dx, dy);
1911		}
1912		else if (dataObj.key == this.edgesKeys[mxGraphMlConstants.EDGE_STYLE].key)
1913		{
1914//			console.log(dataObj);
1915			this.addEdgeStyle(edge, dataObj, style);
1916		}
1917		else if (dataObj.key == this.edgesKeys[mxGraphMlConstants.EDGE_LABELS].key)
1918		{
1919			this.addLabels(edge, dataObj, style, graph);
1920		}
1921		else if (desktopEdgeObj)
1922		{
1923			this.addEdgeStyle(edge, dataObj, style);
1924			var absPoints = this.addEdgePath(edge, desktopEdgeObj["y:Path"], style, dx, dy);
1925
1926			if (desktopEdgeObj["y:EdgeLabel"])
1927				this.addLabels(edge, desktopEdgeObj["y:EdgeLabel"], style, graph, absPoints);
1928
1929			//special case for link edge
1930			//TODO link doesn't support arrow head types
1931			if (style["shape"] != null && style["shape"].indexOf("link") == 0)
1932			{
1933				style["width"] = style["strokeWidth"];
1934				style["strokeWidth"] = 1;
1935			}
1936		}
1937	}
1938
1939	//handle simple ports (exit/entry[X/Y])
1940	if (src.ports && srcPortId)
1941	{
1942		var srcPort = src.ports[srcPortId];
1943
1944		if (srcPort.pos)
1945		{
1946			style["exitX"] = srcPort.pos.x;
1947			style["exitY"] = srcPort.pos.y;
1948		}
1949	}
1950
1951	if (trg.ports && trgPortId)
1952	{
1953		var trgPort = trg.ports[trgPortId];
1954
1955		if (trgPort.pos)
1956		{
1957			style["entryX"] = trgPort.pos.x;
1958			style["entryY"] = trgPort.pos.y;
1959		}
1960	}
1961
1962	edge.style = this.styleMap2Str(style);
1963
1964	return edge;
1965};
1966
1967mxGraphMlCodec.prototype.addEdgeGeo = function (edge, geoObj, dx, dy)
1968{
1969	var list = geoObj[mxGraphMlConstants.Y_BEND];
1970
1971	if (list)
1972	{
1973		var points = [];
1974
1975		for (var i = 0; i < list.length; i++) {
1976			var pointStr = list[i][mxGraphMlConstants.LOCATION];
1977
1978			if (pointStr) {
1979				var xy = pointStr.split(',');
1980				points.push(new mxPoint(parseFloat(xy[0]) - dx, parseFloat(xy[1]) - dy));
1981			}
1982		}
1983
1984		edge.geometry.points = points;
1985	}
1986};
1987
1988mxGraphMlCodec.prototype.addEdgePath = function (edge, pathObj, style, dx, dy)
1989{
1990	var absPoints = [];
1991	if (pathObj)
1992	{
1993		var srcX = parseFloat(pathObj.sx), srcY = parseFloat(pathObj.sy),
1994				trgX = parseFloat(pathObj.tx), trgY = parseFloat(pathObj.ty);
1995
1996		var srcGeo = edge.source.geometry;
1997		if (srcX != 0 || srcY != 0)
1998		{
1999			style["exitX"] = (srcX + srcGeo.width/2) / srcGeo.width;
2000			style["exitY"] = (srcY + srcGeo.height/2) / srcGeo.height;
2001			absPoints.push(new mxPoint(srcGeo.x + style["exitX"] * srcGeo.width - dx, srcGeo.y + style["exitY"] * srcGeo.height - dy));
2002		}
2003		else
2004		{
2005			absPoints.push(new mxPoint(srcGeo.x + srcGeo.width/2 - dx, srcGeo.y + srcGeo.height/2 - dy));
2006		}
2007
2008		var endP = null;
2009		var trgGeo = edge.target.geometry;
2010		if (trgX != 0 || trgY != 0)
2011		{
2012			style["entryX"] = (trgX + trgGeo.width/2) / trgGeo.width;
2013			style["entryY"] = (trgY + trgGeo.height/2) / trgGeo.height;
2014			endP = new mxPoint(trgGeo.x + style["entryX"] * trgGeo.width - dx, trgGeo.y + style["entryY"] * trgGeo.height - dy);
2015		}
2016		else
2017		{
2018			endP = new mxPoint(trgGeo.x + trgGeo.width/2 - dx, trgGeo.y + trgGeo.height/2 - dy);
2019		}
2020
2021		var list = pathObj["y:Point"];
2022
2023		if (list)
2024		{
2025			if (!(list instanceof Array))
2026			{
2027				list = [list];
2028			}
2029
2030			var points = [];
2031
2032			for (var i = 0; i < list.length; i++)
2033			{
2034				var p = new mxPoint(parseFloat(list[i].x) - dx, parseFloat(list[i].y) - dy)
2035				points.push(p);
2036				absPoints.push(p);
2037			}
2038
2039			edge.geometry.points = points;
2040		}
2041
2042		absPoints.push(endP);
2043	}
2044	return absPoints;
2045};
2046
2047//TODO improve similarity handling
2048mxGraphMlCodec.prototype.addEdgeStyle = function (edge, styleObj, styleMap)
2049{
2050	var dashStyleFn = function(val, map)
2051	{
2052		map["dashed"] = 1;
2053		//map["fixDash"] = 1;
2054		var pattern = null;
2055		switch(val)
2056		{
2057			case "DashDot":
2058				pattern = "3 1 1 1";
2059			break;
2060			case "Dot":
2061				pattern = "1 1";
2062			break;
2063			case "DashDotDot":
2064				pattern = "3 1 1 1 1 1";
2065			break;
2066			case "Dash":
2067				pattern = "3 1";
2068			break;
2069			default:
2070				pattern = val.replace(/0/g, '1');
2071		}
2072
2073		if (pattern)
2074		{
2075			//Some patterns in graphML has only one number
2076			if (pattern.indexOf(" ") < 0)
2077			{
2078				pattern = pattern + " " + pattern;
2079			}
2080			map["dashPattern"] = pattern;
2081		}
2082	};
2083
2084	var desktopLineStyleFn = function(val, map)
2085	{
2086		if (val != "line")
2087			map["dashed"] = 1;
2088
2089		var pattern = null;
2090
2091		switch(val)
2092		{
2093			case "dashed":
2094				pattern = "3 1";
2095			break;
2096			case "dotted":
2097				pattern = "1 1";
2098			break;
2099			case "dashed_dotted":
2100				pattern = "3 2 1 2";
2101			break;
2102		}
2103
2104		if (pattern)
2105			map["dashPattern"] = pattern;
2106	};
2107
2108	// can be mapping to WHITE => empty, BLACK => filled
2109	var endArrowFill = function(val, map)
2110	{
2111		map["endFill"] = (val == 'WHITE' || val.indexOf("white_") == 0 || val.indexOf("transparent_") == 0)? "0" : "1";
2112	};
2113	// can be mapping to WHITE => empty, BLACK => filled
2114	var startArrowFill = function(val, map)
2115	{
2116		map["startFill"] = (val == 'WHITE' || val.indexOf("white_") == 0 || val.indexOf("transparent_") == 0)? "0" : "1";
2117	};
2118
2119	var startArrow = function(val, map)
2120	{
2121		map["startArrow"] = mxGraphMlArrowsMap[val] || "classic";
2122		startArrowFill(val, map);
2123	};
2124
2125	var endArrow = function(val, map)
2126	{
2127		map["endArrow"] = mxGraphMlArrowsMap[val] || "classic";
2128		endArrowFill(val, map);
2129	}
2130
2131	var desktopEdge = {
2132		"defaults" :
2133		{
2134			"rounded": 0,
2135			"endArrow": "none"
2136		},
2137		"configuration": {key: "shape", mod: "shape"},
2138		"y:LineStyle": {
2139			"color": {key: "strokeColor", mod: "color"},
2140			"type": desktopLineStyleFn,
2141			"width": "strokeWidth"
2142		},
2143		"y:Arrows": {
2144			"source": startArrow,
2145			"target": endArrow
2146		},
2147		"y:BendStyle": {
2148			"smoothed": {key: "rounded", mod: "bool"}
2149		}
2150	};
2151
2152	var arcEdgeStyle = mxUtils.clone(desktopEdge);
2153	arcEdgeStyle["defaults"]["curved"] = "1";
2154
2155	this.mapObject(styleObj, {
2156		"yjs:PolylineEdgeStyle": {
2157			"defaults" :
2158			{
2159				"endArrow": "none",
2160				"rounded": 0
2161			},
2162			"smoothingLength": function(val, map)
2163			{
2164				map["rounded"] = (val && parseFloat(val) > 0)? "1" : "0";
2165			},
2166			"stroke": {key: "strokeColor", mod: "color"},
2167			"stroke.yjs:Stroke":
2168			{
2169				"dashStyle": dashStyleFn,
2170				"dashStyle.yjs:DashStyle.dashes": dashStyleFn,
2171				"fill": {key: "strokeColor", mod: "color"},
2172				"fill.yjs:SolidColorFill.color": {key: "strokeColor", mod: "color"},
2173				//"lineCap": "", //??
2174				"thickness.sys:Double": "strokeWidth",
2175				"thickness": "strokeWidth"
2176			},
2177			"targetArrow": {key: "endArrow", mod: "arrow"},
2178			"targetArrow.yjs:Arrow": {
2179				"defaults" :
2180				{
2181					"endArrow": "classic",
2182					"endFill": "1",
2183					"endSize": "6"
2184				},
2185//				cropLength: "", //??
2186				"fill": endArrowFill,
2187				"scale": {key: "endSize", mod: "scale", scale: 5},
2188//				stroke: "", //?
2189				"type": {key: "endArrow", mod: "arrow"}
2190			},
2191			"sourceArrow": {key: "startArrow", mod: "arrow"},
2192			"sourceArrow.yjs:Arrow": {
2193				"defaults" :
2194				{
2195					"startArrow": "classic",
2196					"startFill": "1",
2197					"startSize": "6"
2198				},
2199//				cropLength: "", //??
2200				"fill": startArrowFill,
2201				"scale": {key: "startSize", mod: "scale", scale: 5},
2202//				stroke: "", //?
2203				"type": {key: "startArrow", mod: "arrow"}
2204			}
2205		},
2206		"y:PolyLineEdge": desktopEdge,
2207		"y:GenericEdge": desktopEdge,
2208		//We approximate all curved types with curve
2209		"y:ArcEdge": arcEdgeStyle,
2210		"y:BezierEdge": arcEdgeStyle,
2211		"y:QuadCurveEdge": arcEdgeStyle,
2212		"y:SplineEdge": arcEdgeStyle
2213	}, styleMap);
2214};
2215
2216//TODO label offset
2217//TODO labels object is over swim lanes collapse button
2218mxGraphMlCodec.prototype.addLabels = function (node, lblObj, nodeStyle, graph, absPoints)
2219{
2220	var lastChildIndex = node.getChildCount();
2221	var lblList = lblObj[mxGraphMlConstants.Y_LABEL] || lblObj;
2222
2223	var lblTxts = [];
2224	var lblStyles = [];
2225	var lblLayouts = [];
2226
2227	if (lblList)
2228	{
2229		if (!(lblList instanceof Array))
2230		{
2231			lblList = [lblList];
2232		}
2233
2234		for (var i = 0; i < lblList.length; i++)
2235		{
2236			var lbl = lblList[i];
2237//			console.log(lbl);
2238			var styleMap = {};
2239			var txt = lbl[mxGraphMlConstants.TEXT] || lbl;
2240
2241			if (txt) txt = txt["#text"];
2242
2243			//layout
2244			var layout = lbl[mxGraphMlConstants.LAYOUTPARAMETER] || lbl || {};
2245
2246			//style
2247			var fontStyleFn = function(val, map)
2248			{
2249				if (val)
2250				{
2251					val = val.toUpperCase();
2252				}
2253
2254				var style = map["fontStyle"] || 0;
2255
2256				switch(val)
2257				{
2258					case "ITALIC":
2259						style = style | 2;
2260					break;
2261					case "BOLD":
2262						style = style | 1;
2263					break;
2264					case "UNDERLINE":
2265						style = style | 4;
2266					break;
2267				}
2268				map["fontStyle"] = style;
2269			};
2270
2271			var underlineStyleFn = function(val, map)
2272			{
2273				var style = map["fontStyle"] || 0;
2274
2275				if (val == "true")
2276				{
2277					style = style | 4;
2278				}
2279				map["fontStyle"] = style;
2280			};
2281
2282			this.mapObject(lbl, {
2283				"Style.yjs:DefaultLabelStyle":
2284					{
2285						"backgroundFill" : {key: "labelBackgroundColor", mod: "color"},
2286						"backgroundFill.yjs:SolidColorFill.color" : {key: "labelBackgroundColor", mod: "color"},
2287						"backgroundStroke" : {key: "labelBorderColor", mod: "color"},
2288						"backgroundStroke.yjs:Stroke.fill" : {key: "labelBorderColor", mod: "color"},
2289						"textFill": {key: "fontColor", mod: "color"},
2290						"textFill.yjs:SolidColorFill.color": {key: "fontColor", mod: "color"},
2291						"textSize": "fontSize",
2292						"horizontalTextAlignment": "align",
2293						"verticalTextAlignment": "verticalAlign",
2294						"wrapping": function(val, map)
2295						{
2296							//TODO mxGraph has a single type of wrapping only
2297							if (val)
2298								map["whiteSpace"] = "wrap";
2299						},
2300						"font.yjs:Font":
2301							{
2302								"fontFamily": "fontFamily",
2303								"fontSize": "fontSize",
2304								"fontStyle": fontStyleFn,
2305								"fontWeight": fontStyleFn,
2306								"textDecoration": fontStyleFn
2307							}
2308					},
2309				"Style.y:VoidLabelStyle": function (val, map)
2310					{
2311						map["VoidLbl"] = true;
2312					},
2313				//Desktop format
2314					//hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" iconTextGap="4" modelName="custom" visible="true" width="4.0" x="26.277050018310547" y="70.76200103759766">
2315				"alignment": "align",
2316				//"autoSizePolicy": "",//??
2317				"fontFamily": "fontFamily",
2318				"fontSize": "fontSize",
2319				"fontStyle": fontStyleFn,
2320				"underlinedText": underlineStyleFn,
2321				"horizontalTextPosition": "",//?? how this is compared to alignment?
2322				"textColor": {key: "fontColor", mod: "color"},
2323				"verticalTextPosition": "verticalAlign",
2324				"hasText": {key: "hasText", mod: "bool"},
2325				"rotationAngle": "rotation"
2326			}, styleMap);
2327
2328			if (!styleMap["VoidLbl"] && styleMap["hasText"] != "0")
2329			{
2330				lblTxts.push(txt);
2331				lblStyles.push(styleMap);
2332				lblLayouts.push(layout);
2333			}
2334		}
2335	}
2336
2337	//TODO Use the style map with defaults to change the style
2338	for (var i = 0; i < lblTxts.length; i++)
2339	{
2340		if (lblTxts[i])
2341		{
2342			if (lblLayouts[i] && lblLayouts[i]["bpmn:ParticipantParameter"])
2343				continue;
2344
2345			lblTxts[i] = mxUtils.htmlEntities(lblTxts[i], false).replace(/\n/g, '<br/>');
2346			var geo = node.geometry;
2347
2348			var lblCell = new mxCell(lblTxts[i], new mxGeometry(0, 0, geo.width, geo.height), 'text;html=1;spacing=0;' + this.styleMap2Str(lblStyles[i]));
2349			lblCell.vertex = true;
2350			node.insert(lblCell, lastChildIndex);
2351			var lGeo = lblCell.geometry;
2352
2353//			console.log(lblTxts[i]);
2354//			console.log(lblLayouts[i]);
2355
2356			if (lblLayouts[i]["y:RatioAnchoredLabelModelParameter"])
2357			{
2358				var strSize = mxUtils.getSizeForString(lblTxts[i], lblStyles[i]["fontSize"], lblStyles[i]["fontFamily"]);
2359				var offsetStr = lblLayouts[i]["y:RatioAnchoredLabelModelParameter"]["LayoutOffset"];
2360
2361				if (offsetStr)
2362				{
2363					var parts = offsetStr.split(',');
2364					lGeo.x = parseFloat(parts[0]);
2365					lGeo.y = parseFloat(parts[1]);
2366					lGeo.width = strSize.width;
2367					lGeo.height = strSize.height;
2368					lblCell.style += ";spacingTop=-4;";
2369				}
2370				else
2371				{
2372					//TODO map there?
2373					var lblRatio = lblLayouts[i]["y:RatioAnchoredLabelModelParameter"]["LabelRatio"];
2374					var layoutRatio = lblLayouts[i]["y:RatioAnchoredLabelModelParameter"]["LayoutRatio"];
2375
2376					lblCell.style += ";align=center;";
2377				}
2378			}
2379			else if (lblLayouts[i]["y:InteriorLabelModel"]) //TODO this is probably can be done by setting the value?
2380			{
2381				//TODO merge with next one if they are identical in all cases!
2382				switch (lblLayouts[i]["y:InteriorLabelModel"])
2383				{
2384					case "Center":
2385						lblCell.style += ";verticalAlign=middle;";
2386					break;
2387					case "North":
2388						lGeo.height = 1;
2389					break;
2390					case "West":
2391						lGeo.width = geo.height;
2392						lGeo.height = geo.width;
2393						//-90 rotation of origin
2394						lGeo.y = geo.height /2 - geo.width /2;
2395						lGeo.x = -lGeo.y;
2396						lblCell.style += ";rotation=-90";
2397					break;
2398				}
2399				lblCell.style += ";align=center;";
2400			}
2401			//TODO Spacing still need to be adjusted
2402			else if (lblLayouts[i]["y:StretchStripeLabelModel"] || lblLayouts[i]["y:StripeLabelModelParameter"])
2403			{
2404				//TODO merge with previous one if they are identical in all cases!
2405				var dir = lblLayouts[i]["y:StretchStripeLabelModel"] || lblLayouts[i]["y:StripeLabelModelParameter"]["Position"];
2406				switch (dir)
2407				{
2408					case "North":
2409						lGeo.height = 1;
2410					break;
2411					case "West":
2412						lGeo.width = geo.height;
2413						lGeo.height = geo.width;
2414						//-90 rotation of origin
2415						lGeo.y = geo.height /2 - geo.width /2;
2416						lGeo.x = -lGeo.y;
2417						lblCell.style += ";rotation=-90;";
2418					break;
2419				}
2420			}
2421			else if (lblLayouts[i]["bpmn:PoolHeaderLabelModel"])
2422			{
2423				//TODO merge with previous one if they are identical in all cases!
2424				switch (lblLayouts[i]["bpmn:PoolHeaderLabelModel"])
2425				{
2426					case "NORTH":
2427						lGeo.height = 1;
2428					break;
2429					case "WEST":
2430						lGeo.width = geo.height;
2431						lGeo.height = geo.width;
2432						//-90 rotation of origin
2433						lGeo.y = geo.height /2 - geo.width /2;
2434						lGeo.x = -lGeo.y;
2435						lblCell.style += ";rotation=-90;";
2436					break;
2437				}
2438				lblCell.style += ";align=center;";
2439			}
2440			else if (lblLayouts[i]["y:InteriorStretchLabelModelParameter"])
2441			{
2442				//TODO probably mapObject is needed in this method in general
2443				try {
2444					var insets = lblLayouts[i]["y:InteriorStretchLabelModelParameter"]["Model"]["y:InteriorStretchLabelModel"]["Insets"];
2445					//TODO how to map it?
2446				} catch(e) {
2447					//Ignore
2448				}
2449				lblCell.style += ";align=center;";
2450			}
2451			else if (lblLayouts[i]["y:ExteriorLabelModel"])
2452			{
2453				var lblPos;
2454				switch (lblLayouts[i]["y:ExteriorLabelModel"])
2455				{
2456					case "East":
2457						lblCell.style += ";labelPosition=right;verticalLabelPosition=middle;align=left;verticalAlign=middle;";
2458					break;
2459					case "South":
2460						lblCell.style += ";labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;";
2461					break;
2462					case "North":
2463						lblCell.style += ";labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;"
2464					break;
2465					case "West":
2466						lblCell.style += ";labelPosition=left;verticalLabelPosition=middle;align=right;verticalAlign=middle;";
2467					break;
2468				}
2469			}
2470			else if (lblLayouts[i]["y:FreeEdgeLabelModelParameter"])
2471			{
2472				lGeo.relative = true;
2473				lGeo.adjustIt = true;
2474				var layout = lblLayouts[i]["y:FreeEdgeLabelModelParameter"];
2475				var ratio = layout["Ratio"];
2476				var distance = layout["Distance"];
2477				var angle = layout["Angle"];
2478
2479				//The geometry is adjusted after finishing the graph import (in decode method)
2480				if (ratio)
2481				{
2482					lGeo.x = parseFloat(ratio);
2483				}
2484
2485				if (distance)
2486				{
2487					lGeo.y = parseFloat(distance);
2488				}
2489
2490				if (angle)
2491				{
2492					lblCell.style += ";rotation=" + (parseFloat(angle) * (180 / Math.PI));
2493				}
2494
2495				lblCell.style += ";verticalAlign=middle;";
2496			}
2497			else if (lblLayouts[i]["y:EdgePathLabelModelParameter"])
2498			{
2499				lGeo.relative = true;
2500				var layout = lblLayouts[i]["y:EdgePathLabelModelParameter"];
2501				var side = layout["SideOfEdge"];
2502				var ratio = layout["SegmentRatio"];
2503
2504				lGeo.x = ratio? (2 * parseFloat(ratio) - 1) : 0;
2505
2506				//TODO this is an approximation, it needs to take into consideration the segment direction and label size
2507				if (side)
2508				{
2509					switch(side)
2510					{
2511						case "RightOfEdge":
2512							lGeo.y = -15;
2513						break;
2514						case "LeftOfEdge":
2515							lGeo.y = 15;
2516						break;
2517					}
2518				}
2519
2520				lblCell.style += ";verticalAlign=middle;";
2521
2522			}
2523			else //Desktop format or edge
2524			{
2525				var lblX = parseFloat(lblLayouts[i]["x"]),
2526					lblY = parseFloat(lblLayouts[i]["y"]);
2527
2528				if (lblLayouts[i]["width"]) lGeo.width = parseFloat(lblLayouts[i]["width"]);
2529				if (lblLayouts[i]["height"]) lGeo.height = parseFloat(lblLayouts[i]["height"]);
2530
2531				if (node.edge)
2532				{
2533					lGeo.relative = true;
2534					lGeo.x = 0;
2535					lGeo.y = 0;
2536					var dx = node.source.geometry.getCenterX() - node.target.geometry.getCenterX();
2537					var dy = node.source.geometry.getCenterY() - node.target.geometry.getCenterY();
2538
2539					if (graph && absPoints && lblLayouts[i]["y:ModelParameter"] && lblLayouts[i]["y:ModelParameter"]["y:SmartEdgeLabelModelParameter"])
2540					{
2541						var layout = lblLayouts[i]["y:ModelParameter"]["y:SmartEdgeLabelModelParameter"];
2542						var angle = parseFloat(layout.angle), distance = parseFloat(layout.distance), distanceToCenter = layout.distanceToCenter == "true",
2543							position = layout.position, ratio = parseFloat(layout.ratio), segment = parseFloat(layout.segment);
2544
2545						var eState = new mxCellState();
2546						eState.absolutePoints = absPoints;
2547						graph.view.updateEdgeBounds(eState);
2548						var sign = (position == "left"? 1 : -1);
2549
2550						if (segment == -1 && angle == 6.283185307179586)
2551						{
2552							//TODO FIXME this case is still incorrect
2553							lGeo.offset = new mxPoint(Math.abs(ratio) < 1? eState.segments[0] * ratio : ratio, sign * distance);
2554						}
2555						else
2556						{
2557							if (segment == -1) segment = 0;
2558							//get the edge cell state to get the segments
2559							var dist = 0;
2560							for (var k = 0; k < segment; k++)
2561							{
2562								dist += eState.segments[k];
2563							}
2564
2565							dist += eState.segments[segment] * ratio;
2566							lGeo.x = 2 * (dist / eState.length) - 1;
2567							lGeo.y = ((position == "center"? 0 : distance) + lGeo.height/2 * sign * (Math.abs(dx) > Math.abs(dy)? 1 : -1)) * sign;
2568						}
2569					}
2570					else if (!isNaN(lblX) && !isNaN(lblY))
2571					{
2572						lGeo.offset = new mxPoint(lblX + dx/2 + (dx > 0? -lGeo.width : lGeo.width), lblY);
2573					}
2574				}
2575				else
2576				{
2577					lGeo.x = lblX || 0;
2578					lGeo.y = lblY || 0;
2579				}
2580			}
2581
2582			if (lblStyles[i]["rotation"])
2583			{
2584				//TODO fix label coordinates after rotation
2585				//console.log(lGeo, lblStyles[i]["rotation"]);
2586				if (lblStyles[i]["rotation"] == 270)
2587				{
2588					lGeo.x -= lGeo.height/2;
2589				}
2590			}
2591		}
2592	}
2593	return {lblTxts: lblTxts, lblStyles: lblStyles};
2594};
2595
2596
2597mxGraphMlCodec.prototype.processPage = function (graph, pageIndex)
2598{
2599    var codec = new mxCodec();
2600    var node = codec.encode(graph.getModel());
2601    node.setAttribute("style", "default-style2");
2602    var modelString = mxUtils.getXml(node);
2603
2604    var output = "<diagram name=\"Page " + pageIndex + "\">";
2605    output += Graph.compress(modelString);
2606    output += "</diagram>";
2607    return output;
2608
2609};
2610
2611//These are the same as mxVsdxUtils functions, but added here to be self-dependent
2612/**
2613 * Returns a collection of direct child Elements that match the specified tag name
2614 * @param {*} parent the parent whose direct children will be processed
2615 * @param {string} name the child tag name to match
2616 * @return {*[]} a collection of matching Elements
2617 */
2618mxGraphMlCodec.prototype.getDirectChildNamedElements = function (parent, name) {
2619    var result = ([]);
2620    for (var child = parent.firstChild; child != null; child = child.nextSibling) {
2621        if ((child != null && (child.nodeType == 1)) && (name == child.nodeName)) {
2622            /* add */ result.push(child);
2623        }
2624    }
2625    ;
2626    return result;
2627};
2628
2629mxGraphMlCodec.prototype.getDirectFirstChildNamedElements = function (parent, name) {
2630    for (var child = parent.firstChild; child != null; child = child.nextSibling) {
2631        if ((child != null && (child.nodeType == 1)) && (name == child.nodeName)) {
2632            return child;
2633        }
2634    }
2635    ;
2636    return null;
2637};
2638
2639/**
2640 * Returns a collection of direct child Elements
2641 * @param {*} parent the parent whose direct children will be processed
2642 * @return {*[]} a collection of all child Elements
2643 */
2644mxGraphMlCodec.prototype.getDirectChildElements = function (parent) {
2645    var result = ([]);
2646    for (var child = parent.firstChild; child != null; child = child.nextSibling) {
2647        if (child != null && (child.nodeType == 1)) {
2648            /* add */ result.push(child);
2649        }
2650    }
2651    ;
2652    return result;
2653};
2654/**
2655 * Returns the first direct child Element
2656 * @param {*} parent the parent whose direct first child will be processed
2657 * @return {*} the first child Element
2658 */
2659mxGraphMlCodec.prototype.getDirectFirstChildElement = function (parent) {
2660    for (var child = parent.firstChild; child != null; child = child.nextSibling) {
2661        if (child != null && (child.nodeType == 1)) {
2662            return child;
2663        }
2664    }
2665    ;
2666    return null;
2667};
2668
2669var mxGraphMlConverters = //TODO this code is taken from yworks.com. Is that OK?
2670{
2671	"orgchartconverters.linebreakconverter": function(e, t) {
2672		if (typeof e === "string") {
2673			var i = e;
2674			while (i.length > 20 && i.indexOf(" ") > -1)
2675				i = i.substring(0, i.lastIndexOf(" "));
2676			return t === "true" ? i : e.substring(i.length)
2677		}
2678		return ""
2679	},
2680	"orgchartconverters.borderconverter": function(e, t) {
2681		return typeof e === "boolean" ? e ? "#FFBB33" : "rgba(0,0,0,0)" : "#FFF"
2682	},
2683	"orgchartconverters.addhashconverter": function(e, t) {
2684		return typeof e === "string" ? typeof t === "string" ? "#" + e + t : "#" + e : e
2685	},
2686	"orgchartconverters.intermediateconverter": function(e, t) {
2687		return typeof e === "string" && e.length > 17 ? e.replace(/^(.)(\S*)(.*)/, "$1.$3") : e
2688	},
2689	"orgchartconverters.overviewconverter": function(e, t) {
2690		return typeof e === "string" && e.length > 0 ? e.replace(/^(.)(\S*)(.*)/, "$1.$3") : ""
2691	}
2692};
2693
2694var mxGraphMlArrowsMap =
2695{
2696	"SIMPLE": "open",
2697	"TRIANGLE": "block",
2698	"DIAMOND": "diamond",
2699	"CIRCLE": "oval",
2700	"CROSS": "cross",
2701	"SHORT": "classicThin",
2702	"DEFAULT": "classic",
2703	"NONE": "none",
2704	//desktop
2705	"none": "none",
2706	"white_delta_bar": "block", //FIXME not a match
2707	"delta": "block",
2708	"standard": "classic",
2709	"diamond": "diamond",
2710	"white_diamond": "diamond",
2711	"white_delta": "block",
2712	"plain": "open",
2713	"skewed_dash": "dash",
2714	"concave": "openThin", //FIXME not exact match
2715	"transparent_circle": "oval",
2716	"crows_foot_many": "ERmany",
2717	"crows_foot_one": "ERone",
2718	"crows_foot_one_optional": "ERzeroToOne",
2719	"crows_foot_one_mandatory": "ERmandOne",
2720	"crows_foot_many_optional": "ERzeroToMany",
2721	"crows_foot_many_mandatory": "ERoneToMany",
2722	"white_circle": "oval",
2723	"t_shape": "ERone", //FIXME not a match
2724	"short": "classicThin",
2725	"convex": "", //FIXME not a match
2726	"cross": "cross"
2727
2728};
2729
2730var mxGraphMlShapesMap =
2731{
2732	"star5": "mxgraph.basic.star;flipV=1", //TODO This is not close enough!
2733	"star6": "mxgraph.basic.6_point_star",//;rotation=30", //TODO requires rotation!
2734	"star8": "mxgraph.basic.8_point_star",
2735	"sheared_rectangle": "parallelogram",
2736	"sheared_rectangle2": "parallelogram;flipH=1",
2737	"hexagon": "hexagon",
2738	"octagon": "mxgraph.basic.octagon",
2739	"ellipse": "ellipse",
2740	"round_rectangle": "rect;rounded=1;arcsize=30",
2741	"diamond": "rhombus",
2742	"fat_arrow": "step;perimeter=stepPerimeter",
2743	"fat_arrow2": "step;perimeter=stepPerimeter;flipH=1",
2744	"trapez": "trapezoid;perimeter=trapezoidPerimeter;flipV=1",
2745	"trapez2": "trapezoid;perimeter=trapezoidPerimeter",
2746	"triangle": "triangle",//;rotation=-90", //TODO requires rotation!
2747	"triangle2": "triangle",//;rotation=90", //TODO requires rotation!
2748	"rectangle": "rect",
2749	"rectangle3d": "", //TODO create this shape
2750	"roundrectangle": "rect;rounded=1;arcsize=30",
2751	"fatarrow": "step;perimeter=stepPerimeter",
2752	"fatarrow2": "step;perimeter=stepPerimeter;flipH=1",
2753	"parallelogram": "parallelogram",
2754	"parallelogram2": "parallelogram;flipH=1",
2755	"trapezoid2": "trapezoid;perimeter=trapezoidPerimeter;flipV=1",
2756	"trapezoid": "trapezoid;perimeter=trapezoidPerimeter",
2757	//Bevel TODO make them looks closer to yEd
2758	"bevelnode": "rect;glass=1;",
2759	"bevelnodewithshadow": "rect;glass=1;shadow=1",
2760	"bevelnode2": "rect;glass=1;rounded=1;arcsize=30",
2761	"bevelnode3": "rect;glass=1;rounded=1;arcsize=30;shadow=1",
2762	"shinyplatenode": "rect;glass=1",//;rotation=-90",//TODO requires rotation!
2763	"shinyplatenodewithshadow": "rect;glass=1;shadow=1",//;rotation=-90",//TODO requires rotation!
2764	"shinyplatenode2": "rect;glass=1;rounded=1;arcsize=30",//;rotation=-90",//TODO requires rotation!
2765	"shinyplatenode3": "rect;glass=1;rounded=1;arcsize=30;shadow=1",//;rotation=-90",//TODO requires rotation!
2766	//Table
2767//	"yed_table_node
2768	//flowchart
2769	"process": "mxgraph.flowchart.process",
2770	"decision": "mxgraph.flowchart.decision",
2771	"start1": "mxgraph.flowchart.start_1",
2772	"start2": "mxgraph.flowchart.start_2;aspect=fixed",
2773	"terminator": "mxgraph.flowchart.terminator",
2774	"cloud": "cloud",
2775	"data": "mxgraph.flowchart.data",
2776	"directdata": "mxgraph.flowchart.direct_data",
2777	"database": "mxgraph.flowchart.database",
2778	"document": "mxgraph.flowchart.document",
2779	"predefinedprocess": "mxgraph.flowchart.predefined_process",
2780	"storeddata": "mxgraph.flowchart.stored_data",
2781	"internalstorage": "mxgraph.flowchart.internal_storage",
2782	"sequentialdata": "mxgraph.flowchart.sequential_data;aspect=fixed",
2783	"manualinput": "mxgraph.flowchart.manual_input",
2784	"card": "card;size=10",
2785	"papertype": "mxgraph.flowchart.paper_tape",
2786	"delay": "mxgraph.flowchart.delay",
2787	"display": "mxgraph.flowchart.display",
2788	"manualoperation": "mxgraph.flowchart.manual_operation",
2789	"preparation": "mxgraph.flowchart.preparation",
2790	"looplimit": "mxgraph.flowchart.loop_limit",
2791	"looplimitend": "mxgraph.flowchart.loop_limit;flipV=1",
2792	"onpagereference": "mxgraph.flowchart.on-page_reference;aspect=fixed",
2793	"offpagereference": "mxgraph.flowchart.off-page_reference;aspect=fixed",
2794	"annotation": "mxgraph.flowchart.annotation_1", //TODO not similar!
2795	"usermessage": "mxgraph.arrows2.arrow;dy=0;dx=10;notch=0", //TODO requires rotation!
2796	"networkmessage": "mxgraph.arrows2.arrow;dy=0;dx=0;notch=10",
2797	//The same like above but with "com.yworks.flowchart." prefex. TODO should we just remove the prefex?
2798	"com.yworks.flowchart.start1": "mxgraph.flowchart.start_1",
2799	"com.yworks.flowchart.start2": "mxgraph.flowchart.start_2;aspect=fixed",
2800	"com.yworks.flowchart.terminator": "mxgraph.flowchart.terminator",
2801	"com.yworks.flowchart.process": "mxgraph.flowchart.process",
2802	"com.yworks.flowchart.predefinedprocess": "mxgraph.flowchart.predefined_process",
2803	"com.yworks.flowchart.decision": "mxgraph.flowchart.decision",
2804	"com.yworks.flowchart.looplimit": "mxgraph.flowchart.loop_limit",
2805	"com.yworks.flowchart.looplimitend": "mxgraph.flowchart.loop_limit;flipV=1",
2806	"com.yworks.flowchart.document": "mxgraph.flowchart.document",
2807	"com.yworks.flowchart.data": "mxgraph.flowchart.data",
2808	"com.yworks.flowchart.directdata": "mxgraph.flowchart.direct_data",
2809	"com.yworks.flowchart.storeddata": "mxgraph.flowchart.stored_data",
2810	"com.yworks.flowchart.sequentialdata": "mxgraph.flowchart.sequential_data;aspect=fixed",
2811	"com.yworks.flowchart.database": "mxgraph.flowchart.database",
2812	"com.yworks.flowchart.internalstorage": "mxgraph.flowchart.internal_storage",
2813	"com.yworks.flowchart.manualinput": "mxgraph.flowchart.manual_input",
2814	"com.yworks.flowchart.card": "card;size=10",
2815	"com.yworks.flowchart.papertype": "mxgraph.flowchart.paper_tape",
2816	"com.yworks.flowchart.cloud": "cloud",
2817	"com.yworks.flowchart.delay": "mxgraph.flowchart.delay",
2818	"com.yworks.flowchart.display": "mxgraph.flowchart.display",
2819	"com.yworks.flowchart.manualoperation": "mxgraph.flowchart.manual_operation",
2820	"com.yworks.flowchart.preparation": "mxgraph.flowchart.preparation",
2821	"com.yworks.flowchart.onpagereference": "mxgraph.flowchart.on-page_reference;aspect=fixed",
2822	"com.yworks.flowchart.offpagereference": "mxgraph.flowchart.off-page_reference;aspect=fixed",
2823	"com.yworks.flowchart.usermessage": "mxgraph.arrows2.arrow;dy=0;dx=10;notch=0", //TODO requires rotation!
2824	"com.yworks.flowchart.networkmessage": "mxgraph.arrows2.arrow;dy=0;dx=0;notch=10",
2825	"com.yworks.flowchart.annotation": "mxgraph.flowchart.annotation_1", //TODO not similar!
2826
2827	//icons (network)
2828	"database.svg": "mxgraph.networks.storage", //TODO not similar!
2829	"laptop.svg": "mxgraph.networks.laptop",//TODO not similar!
2830	"server.svg": "mxgraph.networks.server",//TODO not similar!
2831	"smartphone.svg": "mxgraph.networks.mobile",//TODO not similar! //TODO fixed aspect ratio
2832	"switch.svg": "mxgraph.networks.switch",//TODO not similar! //TODO fixed aspect ratio
2833	"wlan.svg": "mxgraph.networks.wireless_hub",//TODO not similar!
2834	"workstation.svg": "mxgraph.networks.pc",//TODO not similar!
2835	//bpmn
2836	"transaction": "ext;double=1;rounded=1",
2837	"sub_process": "ext;rounded=1",
2838	"call_activity": "ext;rounded=1;strokeWidth=3",
2839	//TODO two colors for stroke!
2840	"exclusive_with_marker": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=none;symbol=exclusiveGw",
2841	"event_based": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=boundInt;symbol=multiple",
2842	"parallel": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=none;symbol=parallelGw",
2843	"inclusive": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=end;symbol=general",
2844	"complex": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=none;symbol=complexGw",
2845	"exclusive_event_based": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=standard;symbol=multiple",
2846	"parallel_event_based": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;outline=standard;symbol=parallelMultiple",
2847	//hexagon
2848	"calling_global_conversation": "hexagon;strokeWidth=4",
2849	//mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=general
2850	"message": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=message",
2851	"timer": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=timer",
2852	"escalation": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=escalation",
2853	"conditional": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=conditional",
2854	"link": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=link",
2855	"error": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=error",
2856	"cancel": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=cancel",
2857	"compensation": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=compensation",
2858	"signal": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=signal",
2859	"multiple": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=multiple",
2860	"parallel_multiple": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=parallelMultiple",
2861	"terminate": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;symbol=terminate",
2862
2863//	"com.yworks.bpmn.pool
2864	"com.yworks.bpmn.activity.withshadow": "js:bpmnActivityShadow",
2865	"com.yworks.bpmn.activity": "js:bpmnActivity",
2866	"com.yworks.bpmn.gateway.withshadow": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway;shadow=1",
2867	"com.yworks.bpmn.gateway": "mxgraph.bpmn.shape;perimeter=rhombusPerimeter;background=gateway",
2868	"com.yworks.bpmn.event.withshadow": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter;shadow=1",
2869	"com.yworks.bpmn.event": "mxgraph.bpmn.shape;perimeter=ellipsePerimeter",
2870	"com.yworks.bpmn.conversation.withshadow": "hexagon;shadow=1",
2871	"com.yworks.bpmn.conversation": "hexagon",
2872	"com.yworks.bpmn.artifact.withshadow": "js:bpmnArtifactShadow",
2873	"com.yworks.bpmn.artifact": "js:bpmnArtifact",
2874
2875	bpmnOutline: {
2876		"sub_process_interrupting": "eventInt",
2877		"sub_process_non_interrupting": "eventNonint",
2878		"catching": "catching",
2879		"boundary_interrupting": "boundInt",
2880		"boundary_non_interrupting": "boundNonint",
2881		"throwing": "throwing",
2882		"end": "end",
2883		"event_characteristic_start": "standard",
2884		"event_characteristic_end": "end",
2885		"event_characteristic_intermediate_catching": "catching",
2886		"event_characteristic_start_event_sub_process_interrupting": "eventInt",
2887		"event_characteristic_intermediate_boundary_interrupting": "boundInt"
2888	},
2889	bpmnSymbol: {
2890		"event_type_plain": "general",
2891		"event_type_message": "message",
2892		"event_type_timer": "timer",
2893		"event_type_escalation": "escalation",
2894		"event_type_conditional": "conditional",
2895		"event_type_link": "link",
2896		"event_type_error": "error",
2897		"event_type_cancel": "cancel",
2898		"event_type_compensation": "compensation",
2899		"event_type_signal": "signal",
2900		"event_type_multiple": "multiple",
2901		"event_type_parallel_multiple": "parallelMultiple",
2902		"event_type_terminate": "terminate",
2903		"gateway_type_plain": "",
2904		"gateway_type_data_based_exclusive": "exclusiveGw",
2905		"gateway_type_inclusive": "general;outline=end",
2906		"gateway_type_parallel": "parallelGw",
2907		"gateway_type_complex": "complexGw",
2908		"gateway_type_event_based_exclusive": "multiple;outline=catching",
2909		"gateway_type_event_based_exclusive_start_process": "multiple;outline=standard",
2910		"gateway_type_parallel_event_based_exclusive_start_process": "parallelMultiple;outline=standard",
2911		"conversation_type": "",
2912		"artifact_type_data_object": "js:bpmnDataObject",
2913		"artifact_type_annotation": "mxgraph.flowchart.annotation_1",
2914		"artifact_type_group": "rect;fillColor=none;dashed=1;dashPattern=3 1 1 1;collapsible=0;rounded=1",
2915		"artifact_type_data_store": "datastore",
2916		"artifact_type_reply_message": "message;strokeColor=#000000;fillColor=#A1A1A1",
2917		"artifact_type_request_message": "message",
2918		"connection_type_sequence_flow": "",
2919		"connection_type_default_flow": "",
2920		"connection_type_conditional_flow": "",
2921		"connection_type_association": "",
2922		"connection_type_directed_association": "",
2923		"connection_type_bidirected_association": "",
2924		"connection_type_message_flow": "",
2925		"connection_type_conversation_link": "",
2926		"connection_type_forked_conversation_link": "",
2927		"pool_type_lane_and_column": "",
2928		"pool_type_empty": "",
2929		"pool_type_lane": "",
2930		"pool_type_column": "",
2931		"activity_type": ""
2932	},
2933	//desktop entity relationship
2934	"com.yworks.entityrelationship.big_entity": "js:relationship_big_entity",
2935	"com.yworks.entityrelationship.small_entity" : "ext",
2936	"com.yworks.entityrelationship.relationship": "rhombus",
2937	"com.yworks.entityrelationship.attribute": "js:relationship_attribute",
2938	//SBGN
2939	"com.yworks.sbgn.unspecifiedentity": "ellipse",
2940	"com.yworks.sbgn.simplechemical": "ellipse",
2941	"com.yworks.sbgn.macromolecule": "ext;rounded=1",
2942	"com.yworks.sbgn.nucleicacidfeature": "", //TODO create this shape!
2943	"com.yworks.sbgn.perturbingagent": "", //TODO create this shape!
2944	"com.yworks.sbgn.phenotype": "hexagon;perimeter=hexagonPerimeter2;size=0.2",
2945	"com.yworks.sbgn.emptyset": "lineEllipse;line=vertical;perimeter=ellipsePerimeter",//;rotation=45", //TODO create this shape!
2946	"com.yworks.sbgn.submap": "",  //TODO create this shape!
2947	"com.yworks.sbgn.unitofinformation": "",  //TODO create this shape!
2948	"com.yworks.sbgn.statevariable": "mxgraph.flowchart.terminator",
2949	"com.yworks.sbgn.tag": "offPageConnector;size=0.25", //;rotation=90", //TODO create this shape without rotation!
2950	"com.yworks.sbgn.process": "rect",
2951	"com.yworks.sbgn.operator": "ellipse",
2952
2953	//special edges
2954	"com.yworks.edge.framed": "link",
2955
2956	//Male/Female icons (FIXME Not similar and unsafe as it refers to remote resources)
2957	"usericon_female1.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/100/female1-128.png",
2958	"usericon_female2.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/100/female1-128.png",
2959	"usericon_female3.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/100/female1-128.png",
2960	"usericon_female4.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/100/female1-128.png",
2961	"usericon_female5.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/100/female1-128.png",
2962	"usericon_male1.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/101/malecostume-128.png",
2963	"usericon_male2.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/101/malecostume-128.png",
2964	"usericon_male3.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/101/malecostume-128.png",
2965	"usericon_male4.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/101/malecostume-128.png",
2966	"usericon_male5.svg": "image;image=https://cdn1.iconfinder.com/data/icons/user-pictures/101/malecostume-128.png"
2967};
2968
2969var mxGraphMlConstants =
2970{
2971	ID: "id",
2972
2973	KEY_FOR: "for",
2974
2975	KEY_NAME: "attr.name",
2976
2977	KEY_TYPE: "attr.type",
2978
2979	KEY_YTYPE: "yfiles.type",
2980
2981	GRAPH: "graph",
2982
2983	GRAPHML: "graphml",
2984
2985	NODE: "node",
2986
2987	EDGE: "edge",
2988
2989	HYPEREDGE: "hyperedge",
2990
2991	PORT: "port",
2992
2993	ENDPOINT: "endpoint",
2994
2995	KEY: "key",
2996
2997	DATA: "data",
2998
2999	ALL: "all",
3000
3001	EDGE_SOURCE: "source",
3002
3003	EDGE_SOURCE_PORT: "sourceport",
3004
3005	EDGE_TARGET: "target",
3006
3007	EDGE_TARGET_PORT: "targetport",
3008
3009	EDGE_DIRECTED: "directed",
3010
3011	EDGE_UNDIRECTED: "undirected",
3012
3013	EDGE_DEFAULT: "edgedefault",
3014
3015	PORT_NAME: "name",
3016
3017	HEIGHT: "Height",
3018
3019	WIDTH: "Width",
3020
3021	X: "X",
3022
3023	Y: "Y",
3024
3025	HEIGHT_L: "height",
3026
3027	WIDTH_L: "width",
3028
3029	X_L: "x",
3030
3031	Y_L: "y",
3032
3033	JGRAPH: "jGraph:",
3034
3035	GEOMETRY: "y:Geometry",
3036
3037	FILL: "Fill",
3038
3039	SHAPENODE: "y:ShapeNode",
3040
3041	SHAPEEDGE: "ShapeEdge",
3042
3043	JGRAPH_URL: "http://www.jgraph.com/",
3044
3045	KEY_NODE_ID: "d0",
3046
3047	KEY_NODE_NAME: "nodeData",
3048
3049	KEY_EDGE_ID: "d1",
3050
3051	KEY_EDGE_NAME: "edgeData",
3052
3053	STYLE: "Style",
3054
3055	SHAPE: "Shape",
3056
3057	TYPE: "type",
3058
3059	LABEL: "label",
3060
3061	TEXT: "text",
3062
3063	PROPERTIES: "properties",
3064
3065	SOURCETARGET: "SourceTarget",
3066
3067	RECT: "y:RectD",
3068
3069	NODE_LABELS: "NodeLabels",
3070
3071	NODE_LABEL: "y:NodeLabel",
3072
3073	NODE_GEOMETRY: "NodeGeometry",
3074
3075	USER_TAGS: "UserTags",
3076
3077	NODE_STYLE: "NodeStyle",
3078
3079	NODE_GRAPHICS: "nodegraphics",
3080
3081	NODE_VIEW_STATE: "NodeViewState",
3082
3083	EDGE_LABELS: "EdgeLabels",
3084
3085	EDGE_GEOMETRY: "EdgeGeometry",
3086
3087	EDGE_STYLE: "EdgeStyle",
3088
3089	EDGE_VIEW_STATE: "EdgeViewState",
3090
3091	PORT_LOCATION_PARAMETER: "PortLocationParameter",
3092
3093	PORT_STYLE: "PortStyle",
3094
3095	PORT_VIEW_STATE: "PortViewState",
3096
3097	SHARED_DATA: "SharedData",
3098
3099	Y_SHARED_DATA: "y:SharedData",
3100
3101	X_KEY: "x:Key",
3102
3103	GRAPHML_REFERENCE: "y:GraphMLReference",
3104
3105	RESOURCE_KEY: "ResourceKey",
3106
3107	Y_RESOURCES: "y:Resources",
3108
3109	Y_RESOURCE: "y:Resource",
3110
3111	REFID: "refid",
3112
3113	X_LIST: "x:List",
3114
3115	X_STATIC: "x:Static",
3116
3117	Y_BEND: "y:Bend",
3118
3119	LOCATION: "Location",
3120
3121	Y_LABEL: "y:Label",
3122
3123	LAYOUTPARAMETER: "LayoutParameter",
3124
3125	YJS_DEFAULTLABELSTYLE: "yjs:DefaultLabelStyle",
3126
3127	MEMBER: "Member"
3128};
3129
3130
3131EditorUi.prototype.doImportGraphML = function(xmlData, done, onerror)
3132{
3133	new mxGraphMlCodec().decode(xmlData, done, onerror);
3134};
3135
3136