1/**
2 * Copyright (c) 2006-2015, JGraph Ltd
3 */
4
5/**
6 * Registers shapes.
7 */
8(function()
9{
10	// LATER: Use this to implement striping
11	function paintTableBackground(state, c, x, y, w, h, r)
12	{
13		if (state != null)
14		{
15			var graph = state.view.graph;
16			var start = graph.getActualStartSize(state.cell);
17			var rows = graph.model.getChildCells(state.cell, true);
18
19			if (rows.length > 0)
20			{
21				var events = false;
22
23				if (this.style != null)
24				{
25					events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
26				}
27
28				if (!events)
29				{
30					c.pointerEvents = false;
31				}
32
33				var evenRowColor = mxUtils.getValue(state.style,
34					'evenRowColor', mxConstants.NONE);
35				var oddRowColor = mxUtils.getValue(state.style,
36					'oddRowColor', mxConstants.NONE);
37				var evenColColor = mxUtils.getValue(state.style,
38					'evenColumnColor', mxConstants.NONE);
39				var oddColColor = mxUtils.getValue(state.style,
40					'oddColumnColor', mxConstants.NONE);
41				var cols = graph.model.getChildCells(rows[0], true);
42
43				// Paints column backgrounds
44				for (var i = 0; i < cols.length; i++)
45				{
46					var clr = (mxUtils.mod(i, 2) == 1) ? evenColColor : oddColColor;
47					var geo = graph.getCellGeometry(cols[i]);
48
49					if (geo != null && clr != mxConstants.NONE)
50					{
51						c.setFillColor(clr);
52						c.begin();
53						c.moveTo(x + geo.x, y + start.y);
54
55						if (r > 0 && i == cols.length - 1)
56						{
57							c.lineTo(x + geo.x + geo.width - r, y);
58							c.quadTo(x + geo.x + geo.width, y, x + geo.x + geo.width, y + r);
59							c.lineTo(x + geo.x + geo.width, y + h - r);
60							c.quadTo(x + geo.x + geo.width, y + h, x + geo.x + geo.width - r, y + h);
61						}
62						else
63						{
64							c.lineTo(x + geo.x + geo.width, y + start.y);
65							c.lineTo(x + geo.x + geo.width, y + h - start.height);
66						}
67
68						c.lineTo(x + geo.x, y + h);
69						c.close();
70						c.fill();
71					}
72				}
73
74				// Paints row backgrounds
75				for (var i = 0; i < rows.length; i++)
76				{
77					var clr = (mxUtils.mod(i, 2) == 1) ? evenRowColor : oddRowColor;
78					var geo = graph.getCellGeometry(rows[i]);
79
80					if (geo != null && clr != mxConstants.NONE)
81					{
82						var b = (i == rows.length - 1) ? y + h : y + geo.y + geo.height;
83						c.setFillColor(clr);
84
85						c.begin();
86						c.moveTo(x + start.x, y + geo.y);
87						c.lineTo(x + w - start.width, y + geo.y);
88
89						if (r > 0 && i == rows.length - 1)
90						{
91							c.lineTo(x + w, b - r);
92							c.quadTo(x + w, b, x + w - r, b);
93							c.lineTo(x + r, b);
94							c.quadTo(x, b, x, b - r);
95						}
96						else
97						{
98							c.lineTo(x + w - start.width, b);
99							c.lineTo(x + start.x, b);
100						}
101
102						c.close();
103						c.fill();
104					}
105				}
106			}
107		}
108	};
109
110	// Table Shape
111	function TableShape()
112	{
113		mxSwimlane.call(this);
114	};
115
116	mxUtils.extend(TableShape, mxSwimlane);
117
118	TableShape.prototype.getLabelBounds = function(rect)
119	{
120		var start = this.getTitleSize();
121
122		if (start == 0)
123		{
124			return mxShape.prototype.getLabelBounds.apply(this, arguments);
125		}
126		else
127		{
128			return mxSwimlane.prototype.getLabelBounds.apply(this, arguments);
129		}
130	};
131
132	TableShape.prototype.paintVertexShape = function(c, x, y, w, h)
133	{
134		// LATER: Split background to add striping
135		//paintTableBackground(this.state, c, x, y, w, h);
136
137		var start = this.getTitleSize();
138
139		if (start == 0)
140		{
141			mxRectangleShape.prototype.paintBackground.apply(this, arguments);
142		}
143		else
144		{
145			mxSwimlane.prototype.paintVertexShape.apply(this, arguments);
146			c.translate(-x, -y);
147		}
148
149		this.paintForeground(c, x, y, w, h);
150	};
151
152	TableShape.prototype.paintForeground = function(c, x, y, w, h)
153	{
154		if (this.state != null)
155		{
156			var flipH = this.flipH;
157			var flipV = this.flipV;
158
159			if (this.direction == mxConstants.DIRECTION_NORTH || this.direction == mxConstants.DIRECTION_SOUTH)
160			{
161				var tmp = flipH;
162				flipH = flipV;
163				flipV = tmp;
164			}
165
166			// Negative transform to avoid save/restore
167			c.rotate(-this.getShapeRotation(), flipH, flipV, x + w / 2, y + h / 2);
168
169			s = this.scale;
170			x = this.bounds.x / s;
171			y = this.bounds.y / s;
172			w = this.bounds.width / s;
173			h = this.bounds.height / s;
174			this.paintTableForeground(c, x, y, w, h);
175		}
176	};
177
178	TableShape.prototype.paintTableForeground = function(c, x, y, w, h)
179	{
180		var graph = this.state.view.graph;
181		var start = graph.getActualStartSize(this.state.cell);
182		var rows = graph.model.getChildCells(this.state.cell, true);
183
184		if (rows.length > 0)
185		{
186			var rowLines = mxUtils.getValue(this.state.style,
187				'rowLines', '1') != '0';
188			var columnLines = mxUtils.getValue(this.state.style,
189				'columnLines', '1') != '0';
190			var geo = graph.getCellGeometry(rows[0]);
191			var cells = graph.model.getChildCells(rows[0], true);
192			var rowData = [{y: (geo != null) ? geo.y + geo.height : 0,
193				x: 0, cells: cells, colspans: []}];
194
195			// Paints row lines
196			if (rowLines)
197			{
198				for (var i = 1; i < rows.length; i++)
199				{
200					geo = graph.getCellGeometry(rows[i]);
201
202					var data = {y: 0, cells: graph.model.
203						getChildCells(rows[i], true),
204						colspans: []};
205					rowData.push(data);
206
207					if (geo != null)
208					{
209						data.y = geo.y + geo.height;
210
211						c.begin();
212						c.moveTo(x + start.x, y + geo.y);
213						var tw = 0;
214
215						for (j = 0; j < data.cells.length; j++)
216						{
217							if (graph.model.isVisible(data.cells[j]))
218							{
219								tw = data.x;
220							}
221							else
222							{
223								if (tw > 0)
224								{
225									c.lineTo(x + tw - start.width, y + geo.y);
226								}
227
228								c.moveTo(x + geo.x + geo.width + start.x, y + geo.y);
229								tw = 0;
230							}
231						}
232
233						c.lineTo(x + w - start.width, y + geo.y);
234						c.end();
235						c.stroke();
236					}
237				}
238			}
239
240			// Paints column lines
241			if (columnLines)
242			{
243				var cols = rowData[0].cells;
244
245				for (var i = 1; i < cols.length; i++)
246				{
247					geo = graph.getCellGeometry(cols[i]);
248
249					if (geo != null)
250					{
251						c.begin();
252						c.moveTo(x + geo.x + start.x, y + start.y);
253						var th = 0;
254
255						for (var j = 0; j < rowData.length; j++)
256						{
257							var data = rowData[j];
258							var colspan = (i == 1) ? parseInt(graph.getCurrentCellStyle(
259								data.cells[i - 1], true)['colspan'] || 1) :
260									rowData[j].colspans[i - 1];
261
262							data.colspans[i] = colspan - 1;
263
264							if (data.colspans[i] < 1)
265							{
266								data.colspans[i] = parseInt(graph.getCurrentCellStyle(
267									data.cells[i], true)['colspan'] || 1);
268								th = data.y;
269							}
270							else
271							{
272								if (th > 0)
273								{
274									c.lineTo(x + geo.x + start.x, y + th - start.height);
275								}
276
277								c.moveTo(x + geo.x + start.x, y + data.y);
278								th = 0;
279							}
280						}
281
282						c.lineTo(x + geo.x + start.x, y + h - start.height);
283						c.end();
284						c.stroke();
285					}
286				}
287			}
288		}
289	};
290
291	mxCellRenderer.registerShape('table', TableShape);
292
293	// Cube Shape, supports size style
294	function CubeShape()
295	{
296		mxCylinder.call(this);
297	};
298	mxUtils.extend(CubeShape, mxCylinder);
299	CubeShape.prototype.size = 20;
300	CubeShape.prototype.darkOpacity = 0;
301	CubeShape.prototype.darkOpacity2 = 0;
302
303	CubeShape.prototype.paintVertexShape = function(c, x, y, w, h)
304	{
305		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
306		var op = Math.max(-1, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'darkOpacity', this.darkOpacity))));
307		var op2 = Math.max(-1, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'darkOpacity2', this.darkOpacity2))));
308		c.translate(x, y);
309
310		c.begin();
311		c.moveTo(0, 0);
312		c.lineTo(w - s, 0);
313		c.lineTo(w, s);
314		c.lineTo(w, h);
315		c.lineTo(s, h);
316		c.lineTo(0, h - s);
317		c.lineTo(0, 0);
318		c.close();
319		c.end();
320		c.fillAndStroke();
321
322		if (!this.outline)
323		{
324			c.setShadow(false);
325
326			if (op != 0)
327			{
328				c.setFillAlpha(Math.abs(op));
329				c.setFillColor((op < 0) ? '#FFFFFF' : '#000000');
330				c.begin();
331				c.moveTo(0, 0);
332				c.lineTo(w - s, 0);
333				c.lineTo(w, s);
334				c.lineTo(s, s);
335				c.close();
336				c.fill();
337			}
338
339			if (op2 != 0)
340			{
341				c.setFillAlpha(Math.abs(op2));
342				c.setFillColor((op2 < 0) ? '#FFFFFF' : '#000000');
343				c.begin();
344				c.moveTo(0, 0);
345				c.lineTo(s, s);
346				c.lineTo(s, h);
347				c.lineTo(0, h - s);
348				c.close();
349				c.fill();
350			}
351
352			c.begin();
353			c.moveTo(s, h);
354			c.lineTo(s, s);
355			c.lineTo(0, 0);
356			c.moveTo(s, s);
357			c.lineTo(w, s);
358			c.end();
359			c.stroke();
360		}
361	};
362	CubeShape.prototype.getLabelMargins = function(rect)
363	{
364		if (mxUtils.getValue(this.style, 'boundedLbl', false))
365		{
366			var s = parseFloat(mxUtils.getValue(this.style, 'size', this.size)) * this.scale;
367
368			return new mxRectangle(s, s, 0, 0);
369		}
370
371		return null;
372	};
373
374	mxCellRenderer.registerShape('cube', CubeShape);
375
376	var tan30 = Math.tan(mxUtils.toRadians(30));
377	var tan30Dx = (0.5 - tan30) / 2;
378
379	mxCellRenderer.registerShape('isoRectangle', IsoRectangleShape);
380
381	// Cube Shape, supports size style
382	function WaypointShape()
383	{
384		mxCylinder.call(this);
385	};
386	mxUtils.extend(WaypointShape, mxCylinder);
387	WaypointShape.prototype.size = 6;
388
389	WaypointShape.prototype.paintVertexShape = function(c, x, y, w, h)
390	{
391		c.setFillColor(this.stroke);
392		var s = Math.max(0, parseFloat(mxUtils.getValue(this.style, 'size', this.size)) - 2) + 2 * this.strokewidth;
393		c.ellipse(x + (w - s) * 0.5, y + (h - s) * 0.5, s, s);
394		c.fill();
395
396		c.setFillColor(mxConstants.NONE);
397		c.rect(x, y, w, h);
398		c.fill();
399	};
400
401	mxCellRenderer.registerShape('waypoint', WaypointShape);
402
403	// Cube Shape, supports size style
404	function IsoRectangleShape()
405	{
406		mxActor.call(this);
407	};
408	mxUtils.extend(IsoRectangleShape, mxActor);
409	IsoRectangleShape.prototype.size = 20;
410	IsoRectangleShape.prototype.redrawPath = function(path, x, y, w, h)
411	{
412		var m = Math.min(w, h / tan30);
413
414		path.translate((w - m) / 2, (h - m) / 2 + m / 4);
415		path.moveTo(0, 0.25 * m);
416		path.lineTo(0.5 * m, m * tan30Dx);
417		path.lineTo(m, 0.25 * m);
418		path.lineTo(0.5 * m, (0.5 - tan30Dx) * m);
419		path.lineTo(0, 0.25 * m);
420		path.close();
421		path.end();
422	};
423
424	mxCellRenderer.registerShape('isoRectangle', IsoRectangleShape);
425
426	// Cube Shape, supports size style
427	function IsoCubeShape()
428	{
429		mxCylinder.call(this);
430	};
431	mxUtils.extend(IsoCubeShape, mxCylinder);
432	IsoCubeShape.prototype.size = 20;
433	IsoCubeShape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
434	{
435		var m = Math.min(w, h / (0.5 + tan30));
436
437		if (isForeground)
438		{
439			path.moveTo(0, 0.25 * m);
440			path.lineTo(0.5 * m, (0.5 - tan30Dx) * m);
441			path.lineTo(m, 0.25 * m);
442			path.moveTo(0.5 * m, (0.5 - tan30Dx) * m);
443			path.lineTo(0.5 * m, (1 - tan30Dx) * m);
444			path.end();
445		}
446		else
447		{
448			path.translate((w - m) / 2, (h - m) / 2);
449			path.moveTo(0, 0.25 * m);
450			path.lineTo(0.5 * m, m * tan30Dx);
451			path.lineTo(m, 0.25 * m);
452			path.lineTo(m, 0.75 * m);
453			path.lineTo(0.5 * m, (1 - tan30Dx) * m);
454			path.lineTo(0, 0.75 * m);
455			path.close();
456			path.end();
457		}
458	};
459
460	mxCellRenderer.registerShape('isoCube', IsoCubeShape);
461
462	// DataStore Shape, supports size style
463	function DataStoreShape()
464	{
465		mxCylinder.call(this);
466	};
467	mxUtils.extend(DataStoreShape, mxCylinder);
468
469	DataStoreShape.prototype.redrawPath = function(c, x, y, w, h, isForeground)
470	{
471		var dy = Math.min(h / 2, Math.round(h / 8) + this.strokewidth - 1);
472
473		if ((isForeground && this.fill != null) || (!isForeground && this.fill == null))
474		{
475			c.moveTo(0, dy);
476			c.curveTo(0, 2 * dy, w, 2 * dy, w, dy);
477
478			// Needs separate shapes for correct hit-detection
479			if (!isForeground)
480			{
481				c.stroke();
482				c.begin();
483			}
484
485			c.translate(0, dy / 2);
486			c.moveTo(0, dy);
487			c.curveTo(0, 2 * dy, w, 2 * dy, w, dy);
488
489			// Needs separate shapes for correct hit-detection
490			if (!isForeground)
491			{
492				c.stroke();
493				c.begin();
494			}
495
496			c.translate(0, dy / 2);
497			c.moveTo(0, dy);
498			c.curveTo(0, 2 * dy, w, 2 * dy, w, dy);
499
500			// Needs separate shapes for correct hit-detection
501			if (!isForeground)
502			{
503				c.stroke();
504				c.begin();
505			}
506
507			c.translate(0, -dy);
508		}
509
510		if (!isForeground)
511		{
512			c.moveTo(0, dy);
513			c.curveTo(0, -dy / 3, w, -dy / 3, w, dy);
514			c.lineTo(w, h - dy);
515			c.curveTo(w, h + dy / 3, 0, h + dy / 3, 0, h - dy);
516			c.close();
517		}
518	};
519	DataStoreShape.prototype.getLabelMargins = function(rect)
520	{
521		return new mxRectangle(0, 2.5 * Math.min(rect.height / 2,
522			Math.round(rect.height / 8) + this.strokewidth - 1), 0, 0);
523	}
524
525	mxCellRenderer.registerShape('datastore', DataStoreShape);
526
527	// Note Shape, supports size style
528	function NoteShape()
529	{
530		mxCylinder.call(this);
531	};
532	mxUtils.extend(NoteShape, mxCylinder);
533	NoteShape.prototype.size = 30;
534	NoteShape.prototype.darkOpacity = 0;
535
536	NoteShape.prototype.paintVertexShape = function(c, x, y, w, h)
537	{
538		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
539		var op = Math.max(-1, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'darkOpacity', this.darkOpacity))));
540		c.translate(x, y);
541
542		c.begin();
543		c.moveTo(0, 0);
544		c.lineTo(w - s, 0);
545		c.lineTo(w, s);
546		c.lineTo(w, h);
547		c.lineTo(0, h);
548		c.lineTo(0, 0);
549		c.close();
550		c.end();
551		c.fillAndStroke();
552
553		if (!this.outline)
554		{
555			c.setShadow(false);
556
557			if (op != 0)
558			{
559				c.setFillAlpha(Math.abs(op));
560				c.setFillColor((op < 0) ? '#FFFFFF' : '#000000');
561				c.begin();
562				c.moveTo(w - s, 0);
563				c.lineTo(w - s, s);
564				c.lineTo(w, s);
565				c.close();
566				c.fill();
567			}
568
569			c.begin();
570			c.moveTo(w - s, 0);
571			c.lineTo(w - s, s);
572			c.lineTo(w, s);
573			c.end();
574			c.stroke();
575		}
576	};
577
578	mxCellRenderer.registerShape('note', NoteShape);
579
580	// Note Shape, supports size style
581	function NoteShape2()
582	{
583		NoteShape.call(this);
584	};
585	mxUtils.extend(NoteShape2, NoteShape);
586
587	mxCellRenderer.registerShape('note2', NoteShape2);
588
589	NoteShape2.prototype.getLabelMargins = function(rect)
590	{
591		if (mxUtils.getValue(this.style, 'boundedLbl', false))
592		{
593			var size = mxUtils.getValue(this.style, 'size', 15);
594
595			return new mxRectangle(0, Math.min(rect.height * this.scale, size * this.scale), 0, 0);
596		}
597
598		return null;
599	};
600
601	// Flexible cube Shape
602	function IsoCubeShape2()
603	{
604		mxShape.call(this);
605	};
606	mxUtils.extend(IsoCubeShape2, mxShape);
607	IsoCubeShape2.prototype.isoAngle = 15;
608
609	IsoCubeShape2.prototype.paintVertexShape = function(c, x, y, w, h)
610	{
611		var isoAngle = Math.max(0.01, Math.min(94, parseFloat(mxUtils.getValue(this.style, 'isoAngle', this.isoAngle)))) * Math.PI / 200 ;
612		var isoH = Math.min(w * Math.tan(isoAngle), h * 0.5);
613
614		c.translate(x,y);
615
616		c.begin();
617		c.moveTo(w * 0.5, 0);
618		c.lineTo(w, isoH);
619		c.lineTo(w, h - isoH);
620		c.lineTo(w * 0.5, h);
621		c.lineTo(0, h - isoH);
622		c.lineTo(0, isoH);
623		c.close();
624		c.fillAndStroke();
625
626		c.setShadow(false);
627
628		c.begin();
629		c.moveTo(0, isoH);
630		c.lineTo(w * 0.5, 2 * isoH);
631		c.lineTo(w, isoH);
632		c.moveTo(w * 0.5, 2 * isoH);
633		c.lineTo(w * 0.5, h);
634		c.stroke();
635	};
636
637	mxCellRenderer.registerShape('isoCube2', IsoCubeShape2);
638
639	// (LEGACY) Flexible cylinder Shape
640	function CylinderShape()
641	{
642		mxShape.call(this);
643	};
644
645	mxUtils.extend(CylinderShape, mxShape);
646
647	CylinderShape.prototype.size = 15;
648
649	CylinderShape.prototype.paintVertexShape = function(c, x, y, w, h)
650	{
651		var size = Math.max(0, Math.min(h * 0.5, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
652
653		c.translate(x,y);
654
655		if (size == 0)
656		{
657			c.rect(0, 0, w, h);
658			c.fillAndStroke();
659		}
660		else
661		{
662			c.begin();
663			c.moveTo(0, size);
664			c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, 0);
665			c.arcTo(w * 0.5, size, 0, 0, 1, w, size);
666			c.lineTo(w, h - size);
667			c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, h);
668			c.arcTo(w * 0.5, size, 0, 0, 1, 0, h - size);
669			c.close();
670			c.fillAndStroke();
671
672			c.setShadow(false);
673
674			c.begin();
675			c.moveTo(w, size);
676			c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, 2 * size);
677			c.arcTo(w * 0.5, size, 0, 0, 1, 0, size);
678			c.stroke();
679		}
680	};
681
682	mxCellRenderer.registerShape('cylinder2', CylinderShape);
683
684	// Flexible cylinder3 Shape with offset label
685	function CylinderShape3(bounds, fill, stroke, strokewidth)
686	{
687		mxShape.call(this);
688		this.bounds = bounds;
689		this.fill = fill;
690		this.stroke = stroke;
691		this.strokewidth = (strokewidth != null) ? strokewidth : 1;
692	};
693
694	mxUtils.extend(CylinderShape3, mxCylinder);
695
696	CylinderShape3.prototype.size = 15;
697
698	CylinderShape3.prototype.paintVertexShape = function(c, x, y, w, h)
699	{
700		var size = Math.max(0, Math.min(h * 0.5, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
701		var lid = mxUtils.getValue(this.style, 'lid', true);
702
703		c.translate(x,y);
704
705		if (size == 0)
706		{
707			c.rect(0, 0, w, h);
708			c.fillAndStroke();
709		}
710		else
711		{
712			c.begin();
713
714			if (lid)
715			{
716				c.moveTo(0, size);
717				c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, 0);
718				c.arcTo(w * 0.5, size, 0, 0, 1, w, size);
719			}
720			else
721			{
722				c.moveTo(0, 0);
723				c.arcTo(w * 0.5, size, 0, 0, 0, w * 0.5, size);
724				c.arcTo(w * 0.5, size, 0, 0, 0, w, 0);
725			}
726
727			c.lineTo(w, h - size);
728			c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, h);
729			c.arcTo(w * 0.5, size, 0, 0, 1, 0, h - size);
730			c.close();
731			c.fillAndStroke();
732
733			c.setShadow(false);
734
735			if (lid)
736			{
737				c.begin();
738				c.moveTo(w, size);
739				c.arcTo(w * 0.5, size, 0, 0, 1, w * 0.5, 2 * size);
740				c.arcTo(w * 0.5, size, 0, 0, 1, 0, size);
741				c.stroke();
742			}
743		}
744	};
745
746	mxCellRenderer.registerShape('cylinder3', CylinderShape3);
747
748	// Switch Shape, supports size style
749	function SwitchShape()
750	{
751		mxActor.call(this);
752	};
753	mxUtils.extend(SwitchShape, mxActor);
754	SwitchShape.prototype.redrawPath = function(c, x, y, w, h)
755	{
756		var curve = 0.5;
757		c.moveTo(0, 0);
758		c.quadTo(w / 2, h * curve,  w, 0);
759		c.quadTo(w * (1 - curve), h / 2, w, h);
760		c.quadTo(w / 2, h * (1 - curve), 0, h);
761		c.quadTo(w * curve, h / 2, 0, 0);
762		c.end();
763	};
764
765	mxCellRenderer.registerShape('switch', SwitchShape);
766
767	// Folder Shape, supports tabWidth, tabHeight styles
768	function FolderShape()
769	{
770		mxCylinder.call(this);
771	};
772	mxUtils.extend(FolderShape, mxCylinder);
773	FolderShape.prototype.tabWidth = 60;
774	FolderShape.prototype.tabHeight = 20;
775	FolderShape.prototype.tabPosition = 'right';
776	FolderShape.prototype.arcSize = 0.1;
777
778	FolderShape.prototype.paintVertexShape = function(c, x, y, w, h)
779	{
780		c.translate(x, y);
781
782		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'tabWidth', this.tabWidth))));
783		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'tabHeight', this.tabHeight))));
784		var tp = mxUtils.getValue(this.style, 'tabPosition', this.tabPosition);
785		var rounded = mxUtils.getValue(this.style, 'rounded', false);
786		var absArcSize = mxUtils.getValue(this.style, 'absoluteArcSize', false);
787		var arcSize = parseFloat(mxUtils.getValue(this.style, 'arcSize', this.arcSize));
788
789		if (!absArcSize)
790		{
791			arcSize = Math.min(w, h) * arcSize;
792		}
793
794		arcSize = Math.min(arcSize, w * 0.5, (h - dy) * 0.5);
795
796		dx = Math.max(dx, arcSize);
797		dx = Math.min(w - arcSize, dx);
798
799		if (!rounded)
800		{
801			arcSize = 0;
802		}
803
804		c.begin();
805
806		if (tp == 'left')
807		{
808			c.moveTo(Math.max(arcSize, 0), dy);
809			c.lineTo(Math.max(arcSize, 0), 0);
810			c.lineTo(dx, 0);
811			c.lineTo(dx, dy);
812		}
813		// Right is default
814		else
815		{
816			c.moveTo(w - dx, dy);
817			c.lineTo(w - dx, 0);
818			c.lineTo(w - Math.max(arcSize, 0), 0);
819			c.lineTo(w - Math.max(arcSize, 0), dy);
820		}
821
822		if (rounded)
823		{
824			c.moveTo(0, arcSize + dy);
825			c.arcTo(arcSize, arcSize, 0, 0, 1, arcSize, dy);
826			c.lineTo(w - arcSize, dy);
827			c.arcTo(arcSize, arcSize, 0, 0, 1, w, arcSize + dy);
828			c.lineTo(w, h - arcSize);
829			c.arcTo(arcSize, arcSize, 0, 0, 1, w - arcSize, h);
830			c.lineTo(arcSize, h);
831			c.arcTo(arcSize, arcSize, 0, 0, 1, 0, h - arcSize);
832		}
833		else
834		{
835			c.moveTo(0, dy);
836			c.lineTo(w, dy);
837			c.lineTo(w, h);
838			c.lineTo(0, h);
839		}
840
841		c.close();
842		c.fillAndStroke();
843
844		c.setShadow(false);
845
846		var sym = mxUtils.getValue(this.style, 'folderSymbol', null);
847
848		if (sym == 'triangle')
849		{
850			c.begin();
851			c.moveTo(w - 30, dy + 20);
852			c.lineTo(w - 20, dy + 10);
853			c.lineTo(w - 10, dy + 20);
854			c.close();
855			c.stroke();
856		}
857	};
858
859	mxCellRenderer.registerShape('folder', FolderShape);
860
861	FolderShape.prototype.getLabelMargins = function(rect)
862	{
863		if (mxUtils.getValue(this.style, 'boundedLbl', false))
864		{
865			var sizeY = mxUtils.getValue(this.style, 'tabHeight', 15) * this.scale;
866
867			if (mxUtils.getValue(this.style, 'labelInHeader', false))
868			{
869				var sizeX = mxUtils.getValue(this.style, 'tabWidth', 15) * this.scale;
870				var sizeY = mxUtils.getValue(this.style, 'tabHeight', 15) * this.scale;
871				var rounded = mxUtils.getValue(this.style, 'rounded', false);
872				var absArcSize = mxUtils.getValue(this.style, 'absoluteArcSize', false);
873				var arcSize = parseFloat(mxUtils.getValue(this.style, 'arcSize', this.arcSize));
874
875				if (!absArcSize)
876				{
877					arcSize = Math.min(rect.width, rect.height) * arcSize;
878				}
879
880				arcSize = Math.min(arcSize, rect.width * 0.5, (rect.height - sizeY) * 0.5);
881
882				if (!rounded)
883				{
884					arcSize = 0;
885				}
886
887				if (mxUtils.getValue(this.style, 'tabPosition', this.tabPosition) == 'left')
888				{
889					return new mxRectangle(arcSize, 0, Math.min(rect.width, rect.width - sizeX), Math.min(rect.height, rect.height - sizeY));
890				}
891				else
892				{
893					return new mxRectangle(Math.min(rect.width, rect.width - sizeX), 0, arcSize, Math.min(rect.height, rect.height - sizeY));
894				}
895			}
896			else
897			{
898				return new mxRectangle(0, Math.min(rect.height, sizeY), 0, 0);
899			}
900		}
901
902		return null;
903	};
904
905	//**********************************************************************************************************************************************************
906	//UML State shape
907	//**********************************************************************************************************************************************************
908	function UMLStateShape()
909	{
910		mxCylinder.call(this);
911	};
912	mxUtils.extend(UMLStateShape, mxCylinder);
913	UMLStateShape.prototype.arcSize = 0.1;
914
915	UMLStateShape.prototype.paintVertexShape = function(c, x, y, w, h)
916	{
917		c.translate(x, y);
918
919		var rounded = mxUtils.getValue(this.style, 'rounded', false);
920		var absArcSize = mxUtils.getValue(this.style, 'absoluteArcSize', false);
921		var arcSize = parseFloat(mxUtils.getValue(this.style, 'arcSize', this.arcSize));
922		var connPoint = mxUtils.getValue(this.style, 'umlStateConnection', null);
923
924		if (!absArcSize)
925		{
926			arcSize = Math.min(w, h) * arcSize;
927		}
928
929		arcSize = Math.min(arcSize, w * 0.5, h * 0.5);
930
931		if (!rounded)
932		{
933			arcSize = 0;
934		}
935
936		var dx = 0;
937
938		if (connPoint != null)
939		{
940			dx = 10;
941		}
942
943		c.begin();
944		c.moveTo(dx, arcSize);
945		c.arcTo(arcSize, arcSize, 0, 0, 1, dx + arcSize, 0);
946		c.lineTo(w - arcSize, 0);
947		c.arcTo(arcSize, arcSize, 0, 0, 1, w, arcSize);
948		c.lineTo(w, h - arcSize);
949		c.arcTo(arcSize, arcSize, 0, 0, 1, w - arcSize, h);
950		c.lineTo(dx + arcSize, h);
951		c.arcTo(arcSize, arcSize, 0, 0, 1, dx, h - arcSize);
952		c.close();
953		c.fillAndStroke();
954
955		c.setShadow(false);
956
957		var sym = mxUtils.getValue(this.style, 'umlStateSymbol', null);
958
959		if (sym == 'collapseState')
960		{
961			c.roundrect(w - 40, h - 20, 10, 10, 3, 3);
962			c.stroke();
963			c.roundrect(w - 20, h - 20, 10, 10, 3, 3);
964			c.stroke();
965			c.begin();
966			c.moveTo(w - 30, h - 15);
967			c.lineTo(w - 20, h - 15);
968			c.stroke();
969		}
970
971		if (connPoint == 'connPointRefEntry')
972		{
973			c.ellipse(0, h * 0.5 - 10, 20, 20);
974			c.fillAndStroke();
975		}
976		else if (connPoint == 'connPointRefExit')
977		{
978			c.ellipse(0, h * 0.5 - 10, 20, 20);
979			c.fillAndStroke();
980
981			c.begin();
982			c.moveTo(5, h * 0.5 - 5);
983			c.lineTo(15, h * 0.5 + 5);
984			c.moveTo(15, h * 0.5 - 5);
985			c.lineTo(5, h * 0.5 + 5);
986			c.stroke();
987		}
988	};
989
990	UMLStateShape.prototype.getLabelMargins = function(rect)
991	{
992		if (mxUtils.getValue(this.style, 'boundedLbl', false))
993		{
994			var connPoint = mxUtils.getValue(this.style, 'umlStateConnection', null);
995
996			if (connPoint != null)
997			{
998				return new mxRectangle(10 * this.scale, 0, 0, 0);
999			}
1000		}
1001
1002		return null;
1003	};
1004
1005	mxCellRenderer.registerShape('umlState', UMLStateShape);
1006
1007	// Card shape
1008	function CardShape()
1009	{
1010		mxActor.call(this);
1011	};
1012	mxUtils.extend(CardShape, mxActor);
1013	CardShape.prototype.size = 30;
1014	CardShape.prototype.isRoundable = function()
1015	{
1016		return true;
1017	};
1018	CardShape.prototype.redrawPath = function(c, x, y, w, h)
1019	{
1020		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
1021		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1022		this.addPoints(c, [new mxPoint(s, 0), new mxPoint(w, 0), new mxPoint(w, h), new mxPoint(0, h), new mxPoint(0, s)],
1023				this.isRounded, arcSize, true);
1024		c.end();
1025	};
1026
1027	mxCellRenderer.registerShape('card', CardShape);
1028
1029	// Tape shape
1030	function TapeShape()
1031	{
1032		mxActor.call(this);
1033	};
1034	mxUtils.extend(TapeShape, mxActor);
1035	TapeShape.prototype.size = 0.4;
1036	TapeShape.prototype.redrawPath = function(c, x, y, w, h)
1037	{
1038		var dy = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1039		var fy = 1.4;
1040
1041		c.moveTo(0, dy / 2);
1042		c.quadTo(w / 4, dy * fy, w / 2, dy / 2);
1043		c.quadTo(w * 3 / 4, dy * (1 - fy), w, dy / 2);
1044		c.lineTo(w, h - dy / 2);
1045		c.quadTo(w * 3 / 4, h - dy * fy, w / 2, h - dy / 2);
1046		c.quadTo(w / 4, h - dy * (1 - fy), 0, h - dy / 2);
1047		c.lineTo(0, dy / 2);
1048		c.close();
1049		c.end();
1050	};
1051
1052	TapeShape.prototype.getLabelBounds = function(rect)
1053	{
1054		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1055		{
1056			var size = mxUtils.getValue(this.style, 'size', this.size);
1057			var w = rect.width;
1058			var h = rect.height;
1059
1060			if (this.direction == null ||
1061					this.direction == mxConstants.DIRECTION_EAST ||
1062					this.direction == mxConstants.DIRECTION_WEST)
1063			{
1064				var dy = h * size;
1065
1066				return new mxRectangle(rect.x, rect.y + dy, w, h - 2 * dy);
1067			}
1068			else
1069			{
1070				var dx = w * size;
1071
1072				return new mxRectangle(rect.x + dx, rect.y, w - 2 * dx, h);
1073			}
1074		}
1075
1076		return rect;
1077	};
1078
1079	mxCellRenderer.registerShape('tape', TapeShape);
1080
1081	// Document shape
1082	function DocumentShape()
1083	{
1084		mxActor.call(this);
1085	};
1086	mxUtils.extend(DocumentShape, mxActor);
1087	DocumentShape.prototype.size = 0.3;
1088	DocumentShape.prototype.getLabelMargins = function(rect)
1089	{
1090		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1091		{
1092			return new mxRectangle(0, 0, 0, parseFloat(mxUtils.getValue(
1093				this.style, 'size', this.size)) * rect.height);
1094		}
1095
1096		return null;
1097	};
1098	DocumentShape.prototype.redrawPath = function(c, x, y, w, h)
1099	{
1100		var dy = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1101		var fy = 1.4;
1102
1103		c.moveTo(0, 0);
1104		c.lineTo(w, 0);
1105		c.lineTo(w, h - dy / 2);
1106		c.quadTo(w * 3 / 4, h - dy * fy, w / 2, h - dy / 2);
1107		c.quadTo(w / 4, h - dy * (1 - fy), 0, h - dy / 2);
1108		c.lineTo(0, dy / 2);
1109		c.close();
1110		c.end();
1111	};
1112
1113	mxCellRenderer.registerShape('document', DocumentShape);
1114
1115	var cylinderGetCylinderSize = mxCylinder.prototype.getCylinderSize;
1116
1117	mxCylinder.prototype.getCylinderSize = function(x, y, w, h)
1118	{
1119		var size = mxUtils.getValue(this.style, 'size');
1120
1121		if (size != null)
1122		{
1123			return h * Math.max(0, Math.min(1, size));
1124		}
1125		else
1126		{
1127			return cylinderGetCylinderSize.apply(this, arguments);
1128		}
1129	};
1130
1131	mxCylinder.prototype.getLabelMargins = function(rect)
1132	{
1133		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1134		{
1135			var size = mxUtils.getValue(this.style, 'size', 0.15) * 2;
1136
1137			return new mxRectangle(0, Math.min(this.maxHeight * this.scale, rect.height * size), 0, 0);
1138		}
1139
1140		return null;
1141	};
1142
1143	CylinderShape3.prototype.getLabelMargins = function(rect)
1144	{
1145		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1146		{
1147			var size = mxUtils.getValue(this.style, 'size', 15);
1148
1149			if (!mxUtils.getValue(this.style, 'lid', true))
1150			{
1151				size /= 2;
1152			}
1153
1154			return new mxRectangle(0, Math.min(rect.height * this.scale, size * 2 * this.scale), 0, Math.max(0, size * 0.3 * this.scale));
1155		}
1156
1157		return null;
1158	};
1159
1160	FolderShape.prototype.getLabelMargins = function(rect)
1161	{
1162		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1163		{
1164			var sizeY = mxUtils.getValue(this.style, 'tabHeight', 15) * this.scale;
1165
1166			if (mxUtils.getValue(this.style, 'labelInHeader', false))
1167			{
1168				var sizeX = mxUtils.getValue(this.style, 'tabWidth', 15) * this.scale;
1169				var sizeY = mxUtils.getValue(this.style, 'tabHeight', 15) * this.scale;
1170				var rounded = mxUtils.getValue(this.style, 'rounded', false);
1171				var absArcSize = mxUtils.getValue(this.style, 'absoluteArcSize', false);
1172				var arcSize = parseFloat(mxUtils.getValue(this.style, 'arcSize', this.arcSize));
1173
1174				if (!absArcSize)
1175				{
1176					arcSize = Math.min(rect.width, rect.height) * arcSize;
1177				}
1178
1179				arcSize = Math.min(arcSize, rect.width * 0.5, (rect.height - sizeY) * 0.5);
1180
1181				if (!rounded)
1182				{
1183					arcSize = 0;
1184				}
1185
1186				if (mxUtils.getValue(this.style, 'tabPosition', this.tabPosition) == 'left')
1187				{
1188					return new mxRectangle(arcSize, 0, Math.min(rect.width, rect.width - sizeX), Math.min(rect.height, rect.height - sizeY));
1189				}
1190				else
1191				{
1192					return new mxRectangle(Math.min(rect.width, rect.width - sizeX), 0, arcSize, Math.min(rect.height, rect.height - sizeY));
1193				}
1194			}
1195			else
1196			{
1197				return new mxRectangle(0, Math.min(rect.height, sizeY), 0, 0);
1198			}
1199		}
1200
1201		return null;
1202	};
1203
1204	UMLStateShape.prototype.getLabelMargins = function(rect)
1205	{
1206		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1207		{
1208			var connPoint = mxUtils.getValue(this.style, 'umlStateConnection', null);
1209
1210			if (connPoint != null)
1211			{
1212				return new mxRectangle(10 * this.scale, 0, 0, 0);
1213			}
1214		}
1215
1216		return null;
1217	};
1218
1219	NoteShape2.prototype.getLabelMargins = function(rect)
1220	{
1221		if (mxUtils.getValue(this.style, 'boundedLbl', false))
1222		{
1223			var size = mxUtils.getValue(this.style, 'size', 15);
1224
1225			return new mxRectangle(0, Math.min(rect.height * this.scale, size * this.scale), 0, Math.max(0, size * this.scale));
1226		}
1227
1228		return null;
1229	};
1230
1231	// Parallelogram shape
1232	function ParallelogramShape()
1233	{
1234		mxActor.call(this);
1235	};
1236	mxUtils.extend(ParallelogramShape, mxActor);
1237	ParallelogramShape.prototype.size = 0.2;
1238	ParallelogramShape.prototype.fixedSize = 20;
1239	ParallelogramShape.prototype.isRoundable = function()
1240	{
1241		return true;
1242	};
1243	ParallelogramShape.prototype.redrawPath = function(c, x, y, w, h)
1244	{
1245		var fixed = mxUtils.getValue(this.style, 'fixedSize', '0') != '0';
1246
1247		var dx = (fixed) ? Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'size', this.fixedSize)))) : w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1248		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1249		this.addPoints(c, [new mxPoint(0, h), new mxPoint(dx, 0), new mxPoint(w, 0), new mxPoint(w - dx, h)],
1250				this.isRounded, arcSize, true);
1251		c.end();
1252	};
1253
1254	mxCellRenderer.registerShape('parallelogram', ParallelogramShape);
1255
1256	// Trapezoid shape
1257	function TrapezoidShape()
1258	{
1259		mxActor.call(this);
1260	};
1261	mxUtils.extend(TrapezoidShape, mxActor);
1262	TrapezoidShape.prototype.size = 0.2;
1263	TrapezoidShape.prototype.fixedSize = 20;
1264	TrapezoidShape.prototype.isRoundable = function()
1265	{
1266		return true;
1267	};
1268	TrapezoidShape.prototype.redrawPath = function(c, x, y, w, h)
1269	{
1270
1271		var fixed = mxUtils.getValue(this.style, 'fixedSize', '0') != '0';
1272
1273		var dx = (fixed) ? Math.max(0, Math.min(w * 0.5, parseFloat(mxUtils.getValue(this.style, 'size', this.fixedSize)))) : w * Math.max(0, Math.min(0.5, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1274		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1275		this.addPoints(c, [new mxPoint(0, h), new mxPoint(dx, 0), new mxPoint(w - dx, 0), new mxPoint(w, h)],
1276				this.isRounded, arcSize, true);
1277	};
1278
1279	mxCellRenderer.registerShape('trapezoid', TrapezoidShape);
1280
1281	// Curly Bracket shape
1282	function CurlyBracketShape()
1283	{
1284		mxActor.call(this);
1285	};
1286	mxUtils.extend(CurlyBracketShape, mxActor);
1287	CurlyBracketShape.prototype.size = 0.5;
1288	CurlyBracketShape.prototype.redrawPath = function(c, x, y, w, h)
1289	{
1290		c.setFillColor(null);
1291		var s = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1292		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1293		this.addPoints(c, [new mxPoint(w, 0), new mxPoint(s, 0), new mxPoint(s, h / 2),
1294		                   new mxPoint(0, h / 2), new mxPoint(s, h / 2), new mxPoint(s, h),
1295		                   new mxPoint(w, h)], this.isRounded, arcSize, false);
1296		c.end();
1297	};
1298
1299	mxCellRenderer.registerShape('curlyBracket', CurlyBracketShape);
1300
1301	// Parallel marker shape
1302	function ParallelMarkerShape()
1303	{
1304		mxActor.call(this);
1305	};
1306	mxUtils.extend(ParallelMarkerShape, mxActor);
1307	ParallelMarkerShape.prototype.redrawPath = function(c, x, y, w, h)
1308	{
1309		c.setStrokeWidth(1);
1310		c.setFillColor(this.stroke);
1311		var w2 = w / 5;
1312		c.rect(0, 0, w2, h);
1313		c.fillAndStroke();
1314		c.rect(2 * w2, 0, w2, h);
1315		c.fillAndStroke();
1316		c.rect(4 * w2, 0, w2, h);
1317		c.fillAndStroke();
1318	};
1319
1320	mxCellRenderer.registerShape('parallelMarker', ParallelMarkerShape);
1321
1322	/**
1323	 * Adds handJiggle style (jiggle=n sets jiggle)
1324	 */
1325	function HandJiggle(canvas, defaultVariation)
1326	{
1327		this.canvas = canvas;
1328
1329		// Avoids "spikes" in the output
1330		this.canvas.setLineJoin('round');
1331		this.canvas.setLineCap('round');
1332
1333		this.defaultVariation = defaultVariation;
1334
1335		this.originalLineTo = this.canvas.lineTo;
1336		this.canvas.lineTo = mxUtils.bind(this, HandJiggle.prototype.lineTo);
1337
1338		this.originalMoveTo = this.canvas.moveTo;
1339		this.canvas.moveTo = mxUtils.bind(this, HandJiggle.prototype.moveTo);
1340
1341		this.originalClose = this.canvas.close;
1342		this.canvas.close = mxUtils.bind(this, HandJiggle.prototype.close);
1343
1344		this.originalQuadTo = this.canvas.quadTo;
1345		this.canvas.quadTo = mxUtils.bind(this, HandJiggle.prototype.quadTo);
1346
1347		this.originalCurveTo = this.canvas.curveTo;
1348		this.canvas.curveTo = mxUtils.bind(this, HandJiggle.prototype.curveTo);
1349
1350		this.originalArcTo = this.canvas.arcTo;
1351		this.canvas.arcTo = mxUtils.bind(this, HandJiggle.prototype.arcTo);
1352	};
1353
1354	HandJiggle.prototype.moveTo = function(endX, endY)
1355	{
1356		this.originalMoveTo.apply(this.canvas, arguments);
1357		this.lastX = endX;
1358		this.lastY = endY;
1359		this.firstX = endX;
1360		this.firstY = endY;
1361	};
1362
1363	HandJiggle.prototype.close = function()
1364	{
1365		if (this.firstX != null && this.firstY != null)
1366		{
1367			this.lineTo(this.firstX, this.firstY);
1368			this.originalClose.apply(this.canvas, arguments);
1369		}
1370
1371		this.originalClose.apply(this.canvas, arguments);
1372	};
1373
1374	HandJiggle.prototype.quadTo = function(x1, y1, x2, y2)
1375	{
1376		this.originalQuadTo.apply(this.canvas, arguments);
1377		this.lastX = x2;
1378		this.lastY = y2;
1379	};
1380
1381	HandJiggle.prototype.curveTo = function(x1, y1, x2, y2, x3, y3)
1382	{
1383		this.originalCurveTo.apply(this.canvas, arguments);
1384		this.lastX = x3;
1385		this.lastY = y3;
1386	};
1387
1388	HandJiggle.prototype.arcTo = function(rx, ry, angle, largeArcFlag, sweepFlag, x, y)
1389	{
1390		this.originalArcTo.apply(this.canvas, arguments);
1391		this.lastX = x;
1392		this.lastY = y;
1393	};
1394
1395	HandJiggle.prototype.lineTo = function(endX, endY)
1396	{
1397		// LATER: Check why this.canvas.lastX cannot be used
1398		if (this.lastX != null && this.lastY != null)
1399		{
1400			var dx = Math.abs(endX - this.lastX);
1401			var dy = Math.abs(endY - this.lastY);
1402			var dist = Math.sqrt(dx * dx + dy * dy);
1403
1404			if (dist < 2)
1405			{
1406				this.originalLineTo.apply(this.canvas, arguments);
1407				this.lastX = endX;
1408				this.lastY = endY;
1409
1410				return;
1411			}
1412
1413			var segs = Math.round(dist / 10);
1414			var variation = this.defaultVariation;
1415
1416			if (segs < 5)
1417			{
1418				segs = 5;
1419				variation /= 3;
1420			}
1421
1422			function sign(x)
1423			{
1424			    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
1425			}
1426
1427			var stepX = sign(endX - this.lastX) * dx / segs;
1428			var stepY = sign(endY - this.lastY) * dy / segs;
1429
1430			var fx = dx / dist;
1431			var fy = dy / dist;
1432
1433			for (var s = 0; s < segs; s++)
1434			{
1435				var x = stepX * s + this.lastX;
1436				var y = stepY * s + this.lastY;
1437
1438				var offset = (Math.random() - 0.5) * variation;
1439				this.originalLineTo.call(this.canvas, x - offset * fy, y - offset * fx);
1440			}
1441
1442			this.originalLineTo.call(this.canvas, endX, endY);
1443			this.lastX = endX;
1444			this.lastY = endY;
1445		}
1446		else
1447		{
1448			this.originalLineTo.apply(this.canvas, arguments);
1449			this.lastX = endX;
1450			this.lastY = endY;
1451		}
1452	};
1453
1454	HandJiggle.prototype.destroy = function()
1455	{
1456		 this.canvas.lineTo = this.originalLineTo;
1457		 this.canvas.moveTo = this.originalMoveTo;
1458		 this.canvas.close = this.originalClose;
1459		 this.canvas.quadTo = this.originalQuadTo;
1460		 this.canvas.curveTo = this.originalCurveTo;
1461		 this.canvas.arcTo = this.originalArcTo;
1462	};
1463
1464	// Installs hand jiggle for comic and sketch style
1465	mxShape.prototype.defaultJiggle = 1.5;
1466
1467	var shapeBeforePaint = mxShape.prototype.beforePaint;
1468	mxShape.prototype.beforePaint = function(c)
1469	{
1470		shapeBeforePaint.apply(this, arguments);
1471
1472		if (c.handJiggle == null)
1473		{
1474			c.handJiggle = this.createHandJiggle(c);
1475		}
1476	};
1477
1478	var shapeAfterPaint = mxShape.prototype.afterPaint;
1479	mxShape.prototype.afterPaint = function(c)
1480	{
1481		shapeAfterPaint.apply(this, arguments);
1482
1483		if (c.handJiggle != null)
1484		{
1485			c.handJiggle.destroy();
1486			delete c.handJiggle;
1487		}
1488	};
1489
1490	// Returns a new HandJiggle canvas
1491	mxShape.prototype.createComicCanvas = function(c)
1492	{
1493		return new HandJiggle(c, mxUtils.getValue(this.style, 'jiggle', this.defaultJiggle));
1494	};
1495
1496	// Overrides to avoid call to rect
1497	mxShape.prototype.createHandJiggle = function(c)
1498	{
1499		if (!this.outline && this.style != null && mxUtils.getValue(this.style, 'comic', '0') != '0')
1500		{
1501			return this.createComicCanvas(c);
1502		}
1503
1504		return null;
1505	};
1506
1507	// Sets default jiggle for diamond
1508	mxRhombus.prototype.defaultJiggle = 2;
1509
1510	// Overrides to avoid call to rect
1511	var mxRectangleShapeIsHtmlAllowed0 = mxRectangleShape.prototype.isHtmlAllowed;
1512	mxRectangleShape.prototype.isHtmlAllowed = function()
1513	{
1514		return !this.outline && (this.style == null || (mxUtils.getValue(this.style, 'comic', '0') == '0' &&
1515			mxUtils.getValue(this.style, 'sketch', (urlParams['rough'] == '1') ? '1' : '0') == '0')) &&
1516			mxRectangleShapeIsHtmlAllowed0.apply(this, arguments);
1517	};
1518
1519	var mxRectangleShapePaintBackground0 = mxRectangleShape.prototype.paintBackground;
1520	mxRectangleShape.prototype.paintBackground = function(c, x, y, w, h)
1521	{
1522		if (c.handJiggle == null || c.handJiggle.constructor != HandJiggle)
1523		{
1524			mxRectangleShapePaintBackground0.apply(this, arguments);
1525		}
1526		else
1527		{
1528			var events = true;
1529
1530			if (this.style != null)
1531			{
1532				events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
1533			}
1534
1535			if (events || (this.fill != null && this.fill != mxConstants.NONE) ||
1536				(this.stroke != null && this.stroke != mxConstants.NONE))
1537			{
1538				if (!events && (this.fill == null || this.fill == mxConstants.NONE))
1539				{
1540					c.pointerEvents = false;
1541				}
1542
1543				c.begin();
1544
1545				if (this.isRounded)
1546				{
1547					var r = 0;
1548
1549					if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
1550					{
1551						r = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
1552							mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
1553					}
1554					else
1555					{
1556						var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
1557							mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
1558						r = Math.min(w * f, h * f);
1559					}
1560
1561					c.moveTo(x + r, y);
1562					c.lineTo(x + w - r, y);
1563					c.quadTo(x + w, y, x + w, y + r);
1564					c.lineTo(x + w, y + h - r);
1565					c.quadTo(x + w, y + h, x + w - r, y + h);
1566					c.lineTo(x + r, y + h);
1567					c.quadTo(x, y + h, x, y + h - r);
1568					c.lineTo(x, y + r);
1569					c.quadTo(x, y, x + r, y);
1570				}
1571				else
1572				{
1573					c.moveTo(x, y);
1574					c.lineTo(x + w, y);
1575					c.lineTo(x + w, y + h);
1576					c.lineTo(x, y + h);
1577					c.lineTo(x, y);
1578				}
1579
1580				// LATER: Check if close is needed here
1581				c.close();
1582				c.end();
1583
1584				c.fillAndStroke();
1585			}
1586		}
1587	};
1588	// End of hand jiggle integration
1589
1590	// Process Shape
1591	function ProcessShape()
1592	{
1593		mxRectangleShape.call(this);
1594	};
1595	mxUtils.extend(ProcessShape, mxRectangleShape);
1596	ProcessShape.prototype.size = 0.1;
1597	ProcessShape.prototype.fixedSize = false;
1598
1599	ProcessShape.prototype.isHtmlAllowed = function()
1600	{
1601		return false;
1602	};
1603	ProcessShape.prototype.getLabelBounds = function(rect)
1604	{
1605		if (mxUtils.getValue(this.state.style, mxConstants.STYLE_HORIZONTAL, true) ==
1606			(this.direction == null ||
1607			this.direction == mxConstants.DIRECTION_EAST ||
1608			this.direction == mxConstants.DIRECTION_WEST))
1609		{
1610			var w = rect.width;
1611			var h = rect.height;
1612			var r = new mxRectangle(rect.x, rect.y, w, h);
1613
1614			var inset = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1615
1616			if (this.isRounded)
1617			{
1618				var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
1619					mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
1620				inset = Math.max(inset, Math.min(w * f, h * f));
1621			}
1622
1623			r.x += Math.round(inset);
1624			r.width -= Math.round(2 * inset);
1625
1626			return r;
1627		}
1628
1629		return rect;
1630	};
1631
1632	ProcessShape.prototype.paintForeground = function(c, x, y, w, h)
1633	{
1634		var isFixedSize = mxUtils.getValue(this.style, 'fixedSize', this.fixedSize);
1635		var inset = parseFloat(mxUtils.getValue(this.style, 'size', this.size));
1636
1637		if (isFixedSize)
1638		{
1639			inset = Math.max(0, Math.min(w, inset));
1640		}
1641		else
1642		{
1643			inset = w * Math.max(0, Math.min(1, inset));
1644		}
1645
1646		if (this.isRounded)
1647		{
1648			var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
1649				mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
1650			inset = Math.max(inset, Math.min(w * f, h * f));
1651		}
1652
1653		// Crisp rendering of inner lines
1654		inset = Math.round(inset);
1655
1656		c.begin();
1657		c.moveTo(x + inset, y);
1658		c.lineTo(x + inset, y + h);
1659		c.moveTo(x + w - inset, y);
1660		c.lineTo(x + w - inset, y + h);
1661		c.end();
1662		c.stroke();
1663		mxRectangleShape.prototype.paintForeground.apply(this, arguments);
1664	};
1665
1666	mxCellRenderer.registerShape('process', ProcessShape);
1667	//Register the same shape with another name for backwards compatibility
1668	mxCellRenderer.registerShape('process2', ProcessShape);
1669
1670	// Transparent Shape
1671	function TransparentShape()
1672	{
1673		mxRectangleShape.call(this);
1674	};
1675	mxUtils.extend(TransparentShape, mxRectangleShape);
1676	TransparentShape.prototype.paintBackground = function(c, x, y, w, h)
1677	{
1678		c.setFillColor(mxConstants.NONE);
1679		c.rect(x, y, w, h);
1680		c.fill();
1681	};
1682	TransparentShape.prototype.paintForeground = function(c, x, y, w, h) 	{ };
1683
1684	mxCellRenderer.registerShape('transparent', TransparentShape);
1685
1686	// Callout shape
1687	function CalloutShape()
1688	{
1689		mxActor.call(this);
1690	};
1691	mxUtils.extend(CalloutShape, mxHexagon);
1692	CalloutShape.prototype.size = 30;
1693	CalloutShape.prototype.position = 0.5;
1694	CalloutShape.prototype.position2 = 0.5;
1695	CalloutShape.prototype.base = 20;
1696	CalloutShape.prototype.getLabelMargins = function()
1697	{
1698		return new mxRectangle(0, 0, 0, parseFloat(mxUtils.getValue(
1699			this.style, 'size', this.size)) * this.scale);
1700	};
1701	CalloutShape.prototype.isRoundable = function()
1702	{
1703		return true;
1704	};
1705	CalloutShape.prototype.redrawPath = function(c, x, y, w, h)
1706	{
1707		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1708		var s = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1709		var dx = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'position', this.position))));
1710		var dx2 = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'position2', this.position2))));
1711		var base = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'base', this.base))));
1712
1713		this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0), new mxPoint(w, h - s),
1714			new mxPoint(Math.min(w, dx + base), h - s), new mxPoint(dx2, h),
1715			new mxPoint(Math.max(0, dx), h - s), new mxPoint(0, h - s)],
1716			this.isRounded, arcSize, true, [4]);
1717	};
1718
1719	mxCellRenderer.registerShape('callout', CalloutShape);
1720
1721	// Step shape
1722	function StepShape()
1723	{
1724		mxActor.call(this);
1725	};
1726	mxUtils.extend(StepShape, mxActor);
1727	StepShape.prototype.size = 0.2;
1728	StepShape.prototype.fixedSize = 20;
1729	StepShape.prototype.isRoundable = function()
1730	{
1731		return true;
1732	};
1733	StepShape.prototype.redrawPath = function(c, x, y, w, h)
1734	{
1735		var fixed = mxUtils.getValue(this.style, 'fixedSize', '0') != '0';
1736		var s = (fixed) ? Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'size', this.fixedSize)))) :
1737			w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1738		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1739		this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w - s, 0), new mxPoint(w, h / 2), new mxPoint(w - s, h),
1740		                   new mxPoint(0, h), new mxPoint(s, h / 2)], this.isRounded, arcSize, true);
1741		c.end();
1742	};
1743
1744	mxCellRenderer.registerShape('step', StepShape);
1745
1746	// Hexagon shape
1747	function HexagonShape()
1748	{
1749		mxActor.call(this);
1750	};
1751	mxUtils.extend(HexagonShape, mxHexagon);
1752	HexagonShape.prototype.size = 0.25;
1753	HexagonShape.prototype.fixedSize = 20;
1754	HexagonShape.prototype.isRoundable = function()
1755	{
1756		return true;
1757	};
1758	HexagonShape.prototype.redrawPath = function(c, x, y, w, h)
1759	{
1760		var fixed = mxUtils.getValue(this.style, 'fixedSize', '0') != '0';
1761		var s = (fixed) ? Math.max(0, Math.min(w * 0.5, parseFloat(mxUtils.getValue(this.style, 'size', this.fixedSize)))) :
1762			w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
1763		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
1764		this.addPoints(c, [new mxPoint(s, 0), new mxPoint(w - s, 0), new mxPoint(w, 0.5 * h), new mxPoint(w - s, h),
1765		                   new mxPoint(s, h), new mxPoint(0, 0.5 * h)], this.isRounded, arcSize, true);
1766	};
1767
1768	mxCellRenderer.registerShape('hexagon', HexagonShape);
1769
1770	// Plus Shape
1771	function PlusShape()
1772	{
1773		mxRectangleShape.call(this);
1774	};
1775	mxUtils.extend(PlusShape, mxRectangleShape);
1776	PlusShape.prototype.isHtmlAllowed = function()
1777	{
1778		return false;
1779	};
1780	PlusShape.prototype.paintForeground = function(c, x, y, w, h)
1781	{
1782		var border = Math.min(w / 5, h / 5) + 1;
1783
1784		c.begin();
1785		c.moveTo(x + w / 2, y + border);
1786		c.lineTo(x + w / 2, y + h - border);
1787		c.moveTo(x + border, y + h / 2);
1788		c.lineTo(x + w - border, y + h / 2);
1789		c.end();
1790		c.stroke();
1791		mxRectangleShape.prototype.paintForeground.apply(this, arguments);
1792	};
1793
1794	mxCellRenderer.registerShape('plus', PlusShape);
1795
1796	// Overrides painting of rhombus shape to allow for double style
1797	var mxRhombusPaintVertexShape = mxRhombus.prototype.paintVertexShape;
1798	mxRhombus.prototype.getLabelBounds = function(rect)
1799	{
1800		if (this.style['double'] == 1)
1801		{
1802			var margin = (Math.max(2, this.strokewidth + 1) * 2 + parseFloat(
1803				this.style[mxConstants.STYLE_MARGIN] || 0)) * this.scale;
1804
1805			return new mxRectangle(rect.x + margin, rect.y + margin,
1806				rect.width - 2 * margin, rect.height - 2 * margin);
1807		}
1808
1809		return rect;
1810	};
1811	mxRhombus.prototype.paintVertexShape = function(c, x, y, w, h)
1812	{
1813		mxRhombusPaintVertexShape.apply(this, arguments);
1814
1815		if (!this.outline && this.style['double'] == 1)
1816		{
1817			var margin = Math.max(2, this.strokewidth + 1) * 2 +
1818				parseFloat(this.style[mxConstants.STYLE_MARGIN] || 0);
1819			x += margin;
1820			y += margin;
1821			w -= 2 * margin;
1822			h -= 2 * margin;
1823
1824			if (w > 0 && h > 0)
1825			{
1826				c.setShadow(false);
1827
1828				// Workaround for closure compiler bug where the lines with x and y above
1829				// are removed if arguments is used as second argument in call below.
1830				mxRhombusPaintVertexShape.apply(this, [c, x, y, w, h]);
1831			}
1832		}
1833	};
1834
1835	// CompositeShape
1836	function ExtendedShape()
1837	{
1838		mxRectangleShape.call(this);
1839	};
1840	mxUtils.extend(ExtendedShape, mxRectangleShape);
1841	ExtendedShape.prototype.isHtmlAllowed = function()
1842	{
1843		return false;
1844	};
1845	ExtendedShape.prototype.getLabelBounds = function(rect)
1846	{
1847		if (this.style['double'] == 1)
1848		{
1849			var margin = (Math.max(2, this.strokewidth + 1) + parseFloat(
1850				this.style[mxConstants.STYLE_MARGIN] || 0)) * this.scale;
1851
1852			return new mxRectangle(rect.x + margin, rect.y + margin,
1853				rect.width - 2 * margin, rect.height - 2 * margin);
1854		}
1855
1856		return rect;
1857	};
1858
1859	ExtendedShape.prototype.paintForeground = function(c, x, y, w, h)
1860	{
1861		if (this.style != null)
1862		{
1863			if (!this.outline && this.style['double'] == 1)
1864			{
1865				var margin = Math.max(2, this.strokewidth + 1) + parseFloat(this.style[mxConstants.STYLE_MARGIN] || 0);
1866				x += margin;
1867				y += margin;
1868				w -= 2 * margin;
1869				h -= 2 * margin;
1870
1871				if (w > 0 && h > 0)
1872				{
1873					mxRectangleShape.prototype.paintBackground.apply(this, arguments);
1874				}
1875			}
1876
1877			c.setDashed(false);
1878
1879			// Draws the symbols defined in the style. The symbols are
1880			// numbered from 1...n. Possible postfixes are align,
1881			// verticalAlign, spacing, arcSpacing, width, height
1882			var counter = 0;
1883			var shape = null;
1884
1885			do
1886			{
1887				shape = mxCellRenderer.defaultShapes[this.style['symbol' + counter]];
1888
1889				if (shape != null)
1890				{
1891					var align = this.style['symbol' + counter + 'Align'];
1892					var valign = this.style['symbol' + counter + 'VerticalAlign'];
1893					var width = this.style['symbol' + counter + 'Width'];
1894					var height = this.style['symbol' + counter + 'Height'];
1895					var spacing = this.style['symbol' + counter + 'Spacing'] || 0;
1896					var vspacing = this.style['symbol' + counter + 'VSpacing'] || spacing;
1897					var arcspacing = this.style['symbol' + counter + 'ArcSpacing'];
1898
1899					if (arcspacing != null)
1900					{
1901						var arcSize = this.getArcSize(w + this.strokewidth, h + this.strokewidth) * arcspacing;
1902						spacing += arcSize;
1903						vspacing += arcSize;
1904					}
1905
1906					var x2 = x;
1907					var y2 = y;
1908
1909					if (align == mxConstants.ALIGN_CENTER)
1910					{
1911						x2 += (w - width) / 2;
1912					}
1913					else if (align == mxConstants.ALIGN_RIGHT)
1914					{
1915						x2 += w - width - spacing;
1916					}
1917					else
1918					{
1919						x2 += spacing;
1920					}
1921
1922					if (valign == mxConstants.ALIGN_MIDDLE)
1923					{
1924						y2 += (h - height) / 2;
1925					}
1926					else if (valign == mxConstants.ALIGN_BOTTOM)
1927					{
1928						y2 += h - height - vspacing;
1929					}
1930					else
1931					{
1932						y2 += vspacing;
1933					}
1934
1935					c.save();
1936
1937					// Small hack to pass style along into subshape
1938					var tmp = new shape();
1939					// TODO: Clone style and override settings (eg. strokewidth)
1940					tmp.style = this.style;
1941					shape.prototype.paintVertexShape.call(tmp, c, x2, y2, width, height);
1942					c.restore();
1943				}
1944
1945				counter++;
1946			}
1947			while (shape != null);
1948		}
1949
1950		// Paints glass effect
1951		mxRectangleShape.prototype.paintForeground.apply(this, arguments);
1952	};
1953
1954	mxCellRenderer.registerShape('ext', ExtendedShape);
1955
1956	// Tape Shape, supports size style
1957	function MessageShape()
1958	{
1959		mxCylinder.call(this);
1960	};
1961	mxUtils.extend(MessageShape, mxCylinder);
1962	MessageShape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
1963	{
1964		if (isForeground)
1965		{
1966			path.moveTo(0, 0);
1967			path.lineTo(w / 2, h / 2);
1968			path.lineTo(w, 0);
1969			path.end();
1970		}
1971		else
1972		{
1973			path.moveTo(0, 0);
1974			path.lineTo(w, 0);
1975			path.lineTo(w, h);
1976			path.lineTo(0, h);
1977			path.close();
1978		}
1979	};
1980
1981	mxCellRenderer.registerShape('message', MessageShape);
1982
1983	// UML Actor Shape
1984	function UmlActorShape()
1985	{
1986		mxShape.call(this);
1987	};
1988	mxUtils.extend(UmlActorShape, mxShape);
1989	UmlActorShape.prototype.paintBackground = function(c, x, y, w, h)
1990	{
1991		c.translate(x, y);
1992
1993		// Head
1994		c.ellipse(w / 4, 0, w / 2, h / 4);
1995		c.fillAndStroke();
1996
1997		c.begin();
1998		c.moveTo(w / 2, h / 4);
1999		c.lineTo(w / 2, 2 * h / 3);
2000
2001		// Arms
2002		c.moveTo(w / 2, h / 3);
2003		c.lineTo(0, h / 3);
2004		c.moveTo(w / 2, h / 3);
2005		c.lineTo(w, h / 3);
2006
2007		// Legs
2008		c.moveTo(w / 2, 2 * h / 3);
2009		c.lineTo(0, h);
2010		c.moveTo(w / 2, 2 * h / 3);
2011		c.lineTo(w, h);
2012		c.end();
2013
2014		c.stroke();
2015	};
2016
2017	// Replaces existing actor shape
2018	mxCellRenderer.registerShape('umlActor', UmlActorShape);
2019
2020	////////////// UML Boundary Shape ///////////////
2021	function UmlBoundaryShape()
2022	{
2023		mxShape.call(this);
2024	};
2025	mxUtils.extend(UmlBoundaryShape, mxShape);
2026	UmlBoundaryShape.prototype.getLabelMargins = function(rect)
2027	{
2028		return new mxRectangle(rect.width / 6, 0, 0, 0);
2029	};
2030	UmlBoundaryShape.prototype.paintBackground = function(c, x, y, w, h)
2031	{
2032		c.translate(x, y);
2033
2034		// Base line
2035		c.begin();
2036		c.moveTo(0, h / 4);
2037		c.lineTo(0, h * 3 / 4);
2038		c.end();
2039		c.stroke();
2040
2041		// Horizontal line
2042		c.begin();
2043		c.moveTo(0, h / 2);
2044		c.lineTo(w / 6, h / 2);
2045		c.end();
2046		c.stroke();
2047
2048		// Circle
2049		c.ellipse(w / 6, 0, w * 5 / 6, h);
2050		c.fillAndStroke();
2051	};
2052
2053	mxCellRenderer.registerShape('umlBoundary', UmlBoundaryShape);
2054
2055	// UML Entity Shape
2056	function UmlEntityShape()
2057	{
2058		mxEllipse.call(this);
2059	};
2060	mxUtils.extend(UmlEntityShape, mxEllipse);
2061	UmlEntityShape.prototype.paintVertexShape = function(c, x, y, w, h)
2062	{
2063		mxEllipse.prototype.paintVertexShape.apply(this, arguments);
2064
2065		c.begin();
2066		c.moveTo(x + w / 8, y + h);
2067		c.lineTo(x + w * 7 / 8, y + h);
2068		c.end();
2069		c.stroke();
2070	};
2071
2072	mxCellRenderer.registerShape('umlEntity', UmlEntityShape);
2073
2074	// UML Destroy Shape
2075	function UmlDestroyShape()
2076	{
2077		mxShape.call(this);
2078	};
2079	mxUtils.extend(UmlDestroyShape, mxShape);
2080	UmlDestroyShape.prototype.paintVertexShape = function(c, x, y, w, h)
2081	{
2082		c.translate(x, y);
2083
2084		c.begin();
2085		c.moveTo(w, 0);
2086		c.lineTo(0, h);
2087		c.moveTo(0, 0);
2088		c.lineTo(w, h);
2089		c.end();
2090		c.stroke();
2091	};
2092
2093	mxCellRenderer.registerShape('umlDestroy', UmlDestroyShape);
2094
2095	// UML Control Shape
2096	function UmlControlShape()
2097	{
2098		mxShape.call(this);
2099	};
2100	mxUtils.extend(UmlControlShape, mxShape);
2101	UmlControlShape.prototype.getLabelBounds = function(rect)
2102	{
2103		return new mxRectangle(rect.x, rect.y + rect.height / 8, rect.width, rect.height * 7 / 8);
2104	};
2105	UmlControlShape.prototype.paintBackground = function(c, x, y, w, h)
2106	{
2107		c.translate(x, y);
2108
2109		// Upper line
2110		c.begin();
2111		c.moveTo(w * 3 / 8, h / 8 * 1.1);
2112		c.lineTo(w * 5 / 8, 0);
2113		c.end();
2114		c.stroke();
2115
2116		// Circle
2117		c.ellipse(0, h / 8, w, h * 7 / 8);
2118		c.fillAndStroke();
2119	};
2120	UmlControlShape.prototype.paintForeground = function(c, x, y, w, h)
2121	{
2122		// Lower line
2123		c.begin();
2124		c.moveTo(w * 3 / 8, h / 8 * 1.1);
2125		c.lineTo(w * 5 / 8, h / 4);
2126		c.end();
2127		c.stroke();
2128	};
2129
2130	// Replaces existing actor shape
2131	mxCellRenderer.registerShape('umlControl', UmlControlShape);
2132
2133	// UML Lifeline Shape
2134	function UmlLifeline()
2135	{
2136		mxRectangleShape.call(this);
2137	};
2138	mxUtils.extend(UmlLifeline, mxRectangleShape);
2139	UmlLifeline.prototype.size = 40;
2140	UmlLifeline.prototype.isHtmlAllowed = function()
2141	{
2142		return false;
2143	};
2144	UmlLifeline.prototype.getLabelBounds = function(rect)
2145	{
2146		var size = Math.max(0, Math.min(rect.height, parseFloat(
2147			mxUtils.getValue(this.style, 'size', this.size)) * this.scale));
2148
2149		return new mxRectangle(rect.x, rect.y, rect.width, size);
2150	};
2151	UmlLifeline.prototype.paintBackground = function(c, x, y, w, h)
2152	{
2153		var size = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
2154		var participant = mxUtils.getValue(this.style, 'participant');
2155
2156		if (participant == null || this.state == null)
2157		{
2158			mxRectangleShape.prototype.paintBackground.call(this, c, x, y, w, size);
2159		}
2160		else
2161		{
2162			var ctor = this.state.view.graph.cellRenderer.getShape(participant);
2163
2164			if (ctor != null && ctor != UmlLifeline)
2165			{
2166				var shape = new ctor();
2167				shape.apply(this.state);
2168				c.save();
2169				shape.paintVertexShape(c, x, y, w, size);
2170				c.restore();
2171			}
2172		}
2173
2174		if (size < h)
2175		{
2176			c.setDashed(mxUtils.getValue(this.style, 'lifelineDashed', '1') == '1');
2177			c.begin();
2178			c.moveTo(x + w / 2, y + size);
2179			c.lineTo(x + w / 2, y + h);
2180			c.end();
2181			c.stroke();
2182		}
2183	};
2184	UmlLifeline.prototype.paintForeground = function(c, x, y, w, h)
2185	{
2186		var size = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
2187		mxRectangleShape.prototype.paintForeground.call(this, c, x, y, w, Math.min(h, size));
2188	};
2189
2190	mxCellRenderer.registerShape('umlLifeline', UmlLifeline);
2191
2192	// UML Frame Shape
2193	function UmlFrame()
2194	{
2195		mxShape.call(this);
2196	};
2197	mxUtils.extend(UmlFrame, mxShape);
2198	UmlFrame.prototype.width = 60;
2199	UmlFrame.prototype.height = 30;
2200	UmlFrame.prototype.corner = 10;
2201	UmlFrame.prototype.getLabelMargins = function(rect)
2202	{
2203		return new mxRectangle(0, 0,
2204			rect.width - (parseFloat(mxUtils.getValue(this.style, 'width', this.width) * this.scale)),
2205			rect.height - (parseFloat(mxUtils.getValue(this.style, 'height', this.height) * this.scale)));
2206	};
2207	UmlFrame.prototype.paintBackground = function(c, x, y, w, h)
2208	{
2209		var co = this.corner;
2210		var w0 = Math.min(w, Math.max(co, parseFloat(mxUtils.getValue(this.style, 'width', this.width))));
2211		var h0 = Math.min(h, Math.max(co * 1.5, parseFloat(mxUtils.getValue(this.style, 'height', this.height))));
2212		var bg = mxUtils.getValue(this.style, mxConstants.STYLE_SWIMLANE_FILLCOLOR, mxConstants.NONE);
2213
2214		if (bg != mxConstants.NONE)
2215		{
2216			c.setFillColor(bg);
2217			c.rect(x, y, w, h);
2218			c.fill();
2219		}
2220
2221		if (this.fill != null && this.fill != mxConstants.NONE && this.gradient && this.gradient != mxConstants.NONE)
2222		{
2223			var b = this.getGradientBounds(c, x, y, w, h);
2224			c.setGradient(this.fill, this.gradient, x, y, w, h, this.gradientDirection);
2225		}
2226		else
2227		{
2228			c.setFillColor(this.fill);
2229		}
2230
2231		c.begin();
2232		c.moveTo(x, y);
2233		c.lineTo(x + w0, y);
2234		c.lineTo(x + w0, y + Math.max(0, h0 - co * 1.5));
2235		c.lineTo(x + Math.max(0, w0 - co), y + h0);
2236		c.lineTo(x, y + h0);
2237		c.close();
2238		c.fillAndStroke();
2239
2240		c.begin();
2241		c.moveTo(x + w0, y);
2242		c.lineTo(x + w, y);
2243		c.lineTo(x + w, y + h);
2244		c.lineTo(x, y + h);
2245		c.lineTo(x, y + h0);
2246		c.stroke();
2247	};
2248
2249	mxCellRenderer.registerShape('umlFrame', UmlFrame);
2250
2251	mxPerimeter.CenterPerimeter = function (bounds, vertex, next, orthogonal)
2252	{
2253		return new mxPoint(bounds.getCenterX(), bounds.getCenterY());
2254	};
2255
2256	mxStyleRegistry.putValue('centerPerimeter', mxPerimeter.CenterPerimeter);
2257
2258	mxPerimeter.LifelinePerimeter = function (bounds, vertex, next, orthogonal)
2259	{
2260		var size = UmlLifeline.prototype.size;
2261
2262		if (vertex != null)
2263		{
2264			size = mxUtils.getValue(vertex.style, 'size', size) * vertex.view.scale;
2265		}
2266
2267		var sw = (parseFloat(vertex.style[mxConstants.STYLE_STROKEWIDTH] || 1) * vertex.view.scale / 2) - 1;
2268
2269		if (next.x < bounds.getCenterX())
2270		{
2271			sw += 1;
2272			sw *= -1;
2273		}
2274
2275		return new mxPoint(bounds.getCenterX() + sw, Math.min(bounds.y + bounds.height,
2276				Math.max(bounds.y + size, next.y)));
2277	};
2278
2279	mxStyleRegistry.putValue('lifelinePerimeter', mxPerimeter.LifelinePerimeter);
2280
2281	mxPerimeter.OrthogonalPerimeter = function (bounds, vertex, next, orthogonal)
2282	{
2283		orthogonal = true;
2284
2285		return mxPerimeter.RectanglePerimeter.apply(this, arguments);
2286	};
2287
2288	mxStyleRegistry.putValue('orthogonalPerimeter', mxPerimeter.OrthogonalPerimeter);
2289
2290	mxPerimeter.BackbonePerimeter = function (bounds, vertex, next, orthogonal)
2291	{
2292		var sw = (parseFloat(vertex.style[mxConstants.STYLE_STROKEWIDTH] || 1) * vertex.view.scale / 2) - 1;
2293
2294		if (vertex.style['backboneSize'] != null)
2295		{
2296			sw += (parseFloat(vertex.style['backboneSize']) * vertex.view.scale / 2) - 1;
2297		}
2298
2299		if (vertex.style[mxConstants.STYLE_DIRECTION] == 'south' ||
2300			vertex.style[mxConstants.STYLE_DIRECTION] == 'north')
2301		{
2302			if (next.x < bounds.getCenterX())
2303			{
2304				sw += 1;
2305				sw *= -1;
2306			}
2307
2308			return new mxPoint(bounds.getCenterX() + sw, Math.min(bounds.y + bounds.height,
2309					Math.max(bounds.y, next.y)));
2310		}
2311		else
2312		{
2313			if (next.y < bounds.getCenterY())
2314			{
2315				sw += 1;
2316				sw *= -1;
2317			}
2318
2319			return new mxPoint(Math.min(bounds.x + bounds.width, Math.max(bounds.x, next.x)),
2320				bounds.getCenterY() + sw);
2321		}
2322	};
2323
2324	mxStyleRegistry.putValue('backbonePerimeter', mxPerimeter.BackbonePerimeter);
2325
2326	// Callout Perimeter
2327	mxPerimeter.CalloutPerimeter = function (bounds, vertex, next, orthogonal)
2328	{
2329		return mxPerimeter.RectanglePerimeter(mxUtils.getDirectedBounds(bounds, new mxRectangle(0, 0, 0,
2330			Math.max(0, Math.min(bounds.height, parseFloat(mxUtils.getValue(vertex.style, 'size',
2331			CalloutShape.prototype.size)) * vertex.view.scale))),
2332			vertex.style), vertex, next, orthogonal);
2333	};
2334
2335	mxStyleRegistry.putValue('calloutPerimeter', mxPerimeter.CalloutPerimeter);
2336
2337	// Parallelogram Perimeter
2338	mxPerimeter.ParallelogramPerimeter = function (bounds, vertex, next, orthogonal)
2339	{
2340		var fixed = mxUtils.getValue(vertex.style, 'fixedSize', '0') != '0';
2341		var size = (fixed) ? ParallelogramShape.prototype.fixedSize : ParallelogramShape.prototype.size;
2342
2343		if (vertex != null)
2344		{
2345			size = mxUtils.getValue(vertex.style, 'size', size);
2346		}
2347
2348		if (fixed)
2349		{
2350			size *= vertex.view.scale;
2351		}
2352
2353		var x = bounds.x;
2354		var y = bounds.y;
2355		var w = bounds.width;
2356		var h = bounds.height;
2357
2358		var direction = (vertex != null) ? mxUtils.getValue(
2359			vertex.style, mxConstants.STYLE_DIRECTION,
2360			mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
2361		var vertical = direction == mxConstants.DIRECTION_NORTH ||
2362			direction == mxConstants.DIRECTION_SOUTH;
2363		var points;
2364
2365		if (vertical)
2366		{
2367			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2368			points = [new mxPoint(x, y), new mxPoint(x + w, y + dy),
2369						new mxPoint(x + w, y + h), new mxPoint(x, y + h - dy), new mxPoint(x, y)];
2370		}
2371		else
2372		{
2373			var dx = (fixed) ? Math.max(0, Math.min(w * 0.5, size)) : w * Math.max(0, Math.min(1, size));
2374			points = [new mxPoint(x + dx, y), new mxPoint(x + w, y),
2375							new mxPoint(x + w - dx, y + h), new mxPoint(x, y + h), new mxPoint(x + dx, y)];
2376		}
2377
2378		var cx = bounds.getCenterX();
2379		var cy = bounds.getCenterY();
2380
2381		var p1 = new mxPoint(cx, cy);
2382
2383		if (orthogonal)
2384		{
2385			if (next.x < x || next.x > x + w)
2386			{
2387				p1.y = next.y;
2388			}
2389			else
2390			{
2391				p1.x = next.x;
2392			}
2393		}
2394
2395		return mxUtils.getPerimeterPoint(points, p1, next);
2396	};
2397
2398	mxStyleRegistry.putValue('parallelogramPerimeter', mxPerimeter.ParallelogramPerimeter);
2399
2400	// Trapezoid Perimeter
2401	mxPerimeter.TrapezoidPerimeter = function (bounds, vertex, next, orthogonal)
2402	{
2403		var fixed = mxUtils.getValue(vertex.style, 'fixedSize', '0') != '0';
2404		var size = (fixed) ? TrapezoidShape.prototype.fixedSize : TrapezoidShape.prototype.size;
2405
2406		if (vertex != null)
2407		{
2408			size = mxUtils.getValue(vertex.style, 'size', size);
2409		}
2410
2411		if (fixed)
2412		{
2413			size *= vertex.view.scale;
2414		}
2415
2416		var x = bounds.x;
2417		var y = bounds.y;
2418		var w = bounds.width;
2419		var h = bounds.height;
2420
2421		var direction = (vertex != null) ? mxUtils.getValue(
2422				vertex.style, mxConstants.STYLE_DIRECTION,
2423				mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
2424		var points = [];
2425
2426		if (direction == mxConstants.DIRECTION_EAST)
2427		{
2428			var dx = (fixed) ? Math.max(0, Math.min(w * 0.5, size)) : w * Math.max(0, Math.min(1, size));
2429			points = [new mxPoint(x + dx, y), new mxPoint(x + w - dx, y),
2430						new mxPoint(x + w, y + h), new mxPoint(x, y + h), new mxPoint(x + dx, y)];
2431		}
2432		else if (direction == mxConstants.DIRECTION_WEST)
2433		{
2434			var dx = (fixed) ? Math.max(0, Math.min(w, size)) : w * Math.max(0, Math.min(1, size));
2435			points = [new mxPoint(x, y), new mxPoint(x + w, y),
2436						new mxPoint(x + w - dx, y + h), new mxPoint(x + dx, y + h), new mxPoint(x, y)];
2437		}
2438		else if (direction == mxConstants.DIRECTION_NORTH)
2439		{
2440			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2441			points = [new mxPoint(x, y + dy), new mxPoint(x + w, y),
2442						new mxPoint(x + w, y + h), new mxPoint(x, y + h - dy), new mxPoint(x, y + dy)];
2443		}
2444		else
2445		{
2446			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2447			points = [new mxPoint(x, y), new mxPoint(x + w, y + dy),
2448						new mxPoint(x + w, y + h - dy), new mxPoint(x, y + h), new mxPoint(x, y)];
2449		}
2450
2451		var cx = bounds.getCenterX();
2452		var cy = bounds.getCenterY();
2453
2454		var p1 = new mxPoint(cx, cy);
2455
2456		if (orthogonal)
2457		{
2458			if (next.x < x || next.x > x + w)
2459			{
2460				p1.y = next.y;
2461			}
2462			else
2463			{
2464				p1.x = next.x;
2465			}
2466		}
2467
2468		return mxUtils.getPerimeterPoint(points, p1, next);
2469	};
2470
2471	mxStyleRegistry.putValue('trapezoidPerimeter', mxPerimeter.TrapezoidPerimeter);
2472
2473	// Step Perimeter
2474	mxPerimeter.StepPerimeter = function (bounds, vertex, next, orthogonal)
2475	{
2476		var fixed = mxUtils.getValue(vertex.style, 'fixedSize', '0') != '0';
2477		var size = (fixed) ? StepShape.prototype.fixedSize : StepShape.prototype.size;
2478
2479		if (vertex != null)
2480		{
2481			size = mxUtils.getValue(vertex.style, 'size', size);
2482		}
2483
2484		if (fixed)
2485		{
2486			size *= vertex.view.scale;
2487		}
2488
2489		var x = bounds.x;
2490		var y = bounds.y;
2491		var w = bounds.width;
2492		var h = bounds.height;
2493
2494		var cx = bounds.getCenterX();
2495		var cy = bounds.getCenterY();
2496
2497		var direction = (vertex != null) ? mxUtils.getValue(
2498				vertex.style, mxConstants.STYLE_DIRECTION,
2499				mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
2500		var points;
2501
2502		if (direction == mxConstants.DIRECTION_EAST)
2503		{
2504			var dx = (fixed) ? Math.max(0, Math.min(w, size)) : w * Math.max(0, Math.min(1, size));
2505			points = [new mxPoint(x, y), new mxPoint(x + w - dx, y), new mxPoint(x + w, cy),
2506							new mxPoint(x + w - dx, y + h), new mxPoint(x, y + h),
2507							new mxPoint(x + dx, cy), new mxPoint(x, y)];
2508		}
2509		else if (direction == mxConstants.DIRECTION_WEST)
2510		{
2511			var dx = (fixed) ? Math.max(0, Math.min(w, size)) : w * Math.max(0, Math.min(1, size));
2512			points = [new mxPoint(x + dx, y), new mxPoint(x + w, y), new mxPoint(x + w - dx, cy),
2513							new mxPoint(x + w, y + h), new mxPoint(x + dx, y + h),
2514							new mxPoint(x, cy), new mxPoint(x + dx, y)];
2515		}
2516		else if (direction == mxConstants.DIRECTION_NORTH)
2517		{
2518			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2519			points = [new mxPoint(x, y + dy), new mxPoint(cx, y), new mxPoint(x + w, y + dy),
2520							new mxPoint(x + w, y + h), new mxPoint(cx, y + h - dy),
2521							new mxPoint(x, y + h), new mxPoint(x, y + dy)];
2522		}
2523		else
2524		{
2525			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2526			points = [new mxPoint(x, y), new mxPoint(cx, y + dy), new mxPoint(x + w, y),
2527							new mxPoint(x + w, y + h - dy), new mxPoint(cx, y + h),
2528							new mxPoint(x, y + h - dy), new mxPoint(x, y)];
2529		}
2530
2531		var p1 = new mxPoint(cx, cy);
2532
2533		if (orthogonal)
2534		{
2535			if (next.x < x || next.x > x + w)
2536			{
2537				p1.y = next.y;
2538			}
2539			else
2540			{
2541				p1.x = next.x;
2542			}
2543		}
2544
2545		return mxUtils.getPerimeterPoint(points, p1, next);
2546	};
2547
2548	mxStyleRegistry.putValue('stepPerimeter', mxPerimeter.StepPerimeter);
2549
2550	// Hexagon Perimeter 2 (keep existing one)
2551	mxPerimeter.HexagonPerimeter2 = function (bounds, vertex, next, orthogonal)
2552	{
2553		var fixed = mxUtils.getValue(vertex.style, 'fixedSize', '0') != '0';
2554		var size = (fixed) ? HexagonShape.prototype.fixedSize : HexagonShape.prototype.size;
2555
2556		if (vertex != null)
2557		{
2558			size = mxUtils.getValue(vertex.style, 'size', size);
2559		}
2560
2561		if (fixed)
2562		{
2563			size *= vertex.view.scale;
2564		}
2565
2566		var x = bounds.x;
2567		var y = bounds.y;
2568		var w = bounds.width;
2569		var h = bounds.height;
2570
2571		var cx = bounds.getCenterX();
2572		var cy = bounds.getCenterY();
2573
2574		var direction = (vertex != null) ? mxUtils.getValue(
2575			vertex.style, mxConstants.STYLE_DIRECTION,
2576			mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
2577		var vertical = direction == mxConstants.DIRECTION_NORTH ||
2578			direction == mxConstants.DIRECTION_SOUTH;
2579		var points;
2580
2581		if (vertical)
2582		{
2583			var dy = (fixed) ? Math.max(0, Math.min(h, size)) : h * Math.max(0, Math.min(1, size));
2584			points = [new mxPoint(cx, y), new mxPoint(x + w, y + dy), new mxPoint(x + w, y + h - dy),
2585							new mxPoint(cx, y + h), new mxPoint(x, y + h - dy),
2586							new mxPoint(x, y + dy), new mxPoint(cx, y)];
2587		}
2588		else
2589		{
2590			var dx = (fixed) ? Math.max(0, Math.min(w, size)) : w * Math.max(0, Math.min(1, size));
2591			points = [new mxPoint(x + dx, y), new mxPoint(x + w - dx, y), new mxPoint(x + w, cy),
2592						new mxPoint(x + w - dx, y + h), new mxPoint(x + dx, y + h),
2593						new mxPoint(x, cy), new mxPoint(x + dx, y)];
2594		}
2595
2596		var p1 = new mxPoint(cx, cy);
2597
2598		if (orthogonal)
2599		{
2600			if (next.x < x || next.x > x + w)
2601			{
2602				p1.y = next.y;
2603			}
2604			else
2605			{
2606				p1.x = next.x;
2607			}
2608		}
2609
2610		return mxUtils.getPerimeterPoint(points, p1, next);
2611	};
2612
2613	mxStyleRegistry.putValue('hexagonPerimeter2', mxPerimeter.HexagonPerimeter2);
2614
2615	// Provided Interface Shape (aka Lollipop)
2616	function LollipopShape()
2617	{
2618		mxShape.call(this);
2619	};
2620	mxUtils.extend(LollipopShape, mxShape);
2621	LollipopShape.prototype.size = 10;
2622	LollipopShape.prototype.paintBackground = function(c, x, y, w, h)
2623	{
2624		var sz = parseFloat(mxUtils.getValue(this.style, 'size', this.size));
2625		c.translate(x, y);
2626
2627		c.ellipse((w - sz) / 2, 0, sz, sz);
2628		c.fillAndStroke();
2629
2630		c.begin();
2631		c.moveTo(w / 2, sz);
2632		c.lineTo(w / 2, h);
2633		c.end();
2634		c.stroke();
2635	};
2636
2637	mxCellRenderer.registerShape('lollipop', LollipopShape);
2638
2639	// Required Interface Shape
2640	function RequiresShape()
2641	{
2642		mxShape.call(this);
2643	};
2644	mxUtils.extend(RequiresShape, mxShape);
2645	RequiresShape.prototype.size = 10;
2646	RequiresShape.prototype.inset = 2;
2647	RequiresShape.prototype.paintBackground = function(c, x, y, w, h)
2648	{
2649		var sz = parseFloat(mxUtils.getValue(this.style, 'size', this.size));
2650		var inset = parseFloat(mxUtils.getValue(this.style, 'inset', this.inset)) + this.strokewidth;
2651		c.translate(x, y);
2652
2653		c.begin();
2654		c.moveTo(w / 2, sz + inset);
2655		c.lineTo(w / 2, h);
2656		c.end();
2657		c.stroke();
2658
2659		c.begin();
2660		c.moveTo((w - sz) / 2 - inset, sz / 2);
2661		c.quadTo((w - sz) / 2 - inset, sz + inset, w / 2, sz + inset);
2662		c.quadTo((w + sz) / 2 + inset, sz + inset, (w + sz) / 2 + inset, sz / 2);
2663		c.end();
2664		c.stroke();
2665	};
2666
2667	mxCellRenderer.registerShape('requires', RequiresShape);
2668
2669	// Required Interface Shape
2670	function RequiredInterfaceShape()
2671	{
2672		mxShape.call(this);
2673	};
2674	mxUtils.extend(RequiredInterfaceShape, mxShape);
2675
2676	RequiredInterfaceShape.prototype.paintBackground = function(c, x, y, w, h)
2677	{
2678		c.translate(x, y);
2679
2680		c.begin();
2681		c.moveTo(0, 0);
2682		c.quadTo(w, 0, w, h / 2);
2683		c.quadTo(w, h, 0, h);
2684		c.end();
2685		c.stroke();
2686	};
2687
2688	mxCellRenderer.registerShape('requiredInterface', RequiredInterfaceShape);
2689
2690	// Provided and Required Interface Shape
2691	function ProvidedRequiredInterfaceShape()
2692	{
2693		mxShape.call(this);
2694	};
2695	mxUtils.extend(ProvidedRequiredInterfaceShape, mxShape);
2696	ProvidedRequiredInterfaceShape.prototype.inset = 2;
2697	ProvidedRequiredInterfaceShape.prototype.paintBackground = function(c, x, y, w, h)
2698	{
2699		var inset = parseFloat(mxUtils.getValue(this.style, 'inset', this.inset)) + this.strokewidth;
2700		c.translate(x, y);
2701
2702		c.ellipse(0, inset, w - 2 * inset, h - 2 * inset);
2703		c.fillAndStroke();
2704
2705		c.begin();
2706		c.moveTo(w / 2, 0);
2707		c.quadTo(w, 0, w, h / 2);
2708		c.quadTo(w, h, w / 2, h);
2709		c.end();
2710		c.stroke();
2711	};
2712
2713	mxCellRenderer.registerShape('providedRequiredInterface', ProvidedRequiredInterfaceShape);
2714
2715	// Module shape
2716	function ModuleShape()
2717	{
2718		mxCylinder.call(this);
2719	};
2720	mxUtils.extend(ModuleShape, mxCylinder);
2721	ModuleShape.prototype.jettyWidth = 20;
2722	ModuleShape.prototype.jettyHeight = 10;
2723	ModuleShape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
2724	{
2725		var dx = parseFloat(mxUtils.getValue(this.style, 'jettyWidth', this.jettyWidth));
2726		var dy = parseFloat(mxUtils.getValue(this.style, 'jettyHeight', this.jettyHeight));
2727		var x0 = dx / 2;
2728		var x1 = x0 + dx / 2;
2729		var y0 = Math.min(dy, h - dy);
2730		var y1 = Math.min(y0 + 2 * dy, h - dy);
2731
2732		if (isForeground)
2733		{
2734			path.moveTo(x0, y0);
2735			path.lineTo(x1, y0);
2736			path.lineTo(x1, y0 + dy);
2737			path.lineTo(x0, y0 + dy);
2738			path.moveTo(x0, y1);
2739			path.lineTo(x1, y1);
2740			path.lineTo(x1, y1 + dy);
2741			path.lineTo(x0, y1 + dy);
2742			path.end();
2743		}
2744		else
2745		{
2746			path.moveTo(x0, 0);
2747			path.lineTo(w, 0);
2748			path.lineTo(w, h);
2749			path.lineTo(x0, h);
2750			path.lineTo(x0, y1 + dy);
2751			path.lineTo(0, y1 + dy);
2752			path.lineTo(0, y1);
2753			path.lineTo(x0, y1);
2754			path.lineTo(x0, y0 + dy);
2755			path.lineTo(0, y0 + dy);
2756			path.lineTo(0, y0);
2757			path.lineTo(x0, y0);
2758			path.close();
2759			path.end();
2760		}
2761	};
2762
2763	mxCellRenderer.registerShape('module', ModuleShape);
2764
2765	// Component shape
2766	function ComponentShape()
2767	{
2768		mxCylinder.call(this);
2769	};
2770	mxUtils.extend(ComponentShape, mxCylinder);
2771	ComponentShape.prototype.jettyWidth = 32;
2772	ComponentShape.prototype.jettyHeight = 12;
2773	ComponentShape.prototype.redrawPath = function(path, x, y, w, h, isForeground)
2774	{
2775		var dx = parseFloat(mxUtils.getValue(this.style, 'jettyWidth', this.jettyWidth));
2776		var dy = parseFloat(mxUtils.getValue(this.style, 'jettyHeight', this.jettyHeight));
2777		var x0 = dx / 2;
2778		var x1 = x0 + dx / 2;
2779		var y0 = 0.3 * h - dy / 2;
2780		var y1 = 0.7 * h - dy / 2;
2781
2782		if (isForeground)
2783		{
2784			path.moveTo(x0, y0);
2785			path.lineTo(x1, y0);
2786			path.lineTo(x1, y0 + dy);
2787			path.lineTo(x0, y0 + dy);
2788			path.moveTo(x0, y1);
2789			path.lineTo(x1, y1);
2790			path.lineTo(x1, y1 + dy);
2791			path.lineTo(x0, y1 + dy);
2792			path.end();
2793		}
2794		else
2795		{
2796			path.moveTo(x0, 0);
2797			path.lineTo(w, 0);
2798			path.lineTo(w, h);
2799			path.lineTo(x0, h);
2800			path.lineTo(x0, y1 + dy);
2801			path.lineTo(0, y1 + dy);
2802			path.lineTo(0, y1);
2803			path.lineTo(x0, y1);
2804			path.lineTo(x0, y0 + dy);
2805			path.lineTo(0, y0 + dy);
2806			path.lineTo(0, y0);
2807			path.lineTo(x0, y0);
2808			path.close();
2809			path.end();
2810		}
2811	};
2812
2813	mxCellRenderer.registerShape('component', ComponentShape);
2814
2815	// Associative entity derived from rectangle shape
2816	function AssociativeEntity()
2817	{
2818		mxRectangleShape.call(this);
2819	};
2820	mxUtils.extend(AssociativeEntity, mxRectangleShape);
2821	AssociativeEntity.prototype.paintForeground = function(c, x, y, w, h)
2822	{
2823		var hw = w / 2;
2824		var hh = h / 2;
2825
2826		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
2827		c.begin();
2828		this.addPoints(c, [new mxPoint(x + hw, y), new mxPoint(x + w, y + hh), new mxPoint(x + hw, y + h),
2829		     new mxPoint(x, y + hh)], this.isRounded, arcSize, true);
2830		c.stroke();
2831
2832		mxRectangleShape.prototype.paintForeground.apply(this, arguments);
2833	};
2834
2835	mxCellRenderer.registerShape('associativeEntity', AssociativeEntity);
2836
2837	// State Shapes derives from double ellipse
2838	function StateShape()
2839	{
2840		mxDoubleEllipse.call(this);
2841	};
2842	mxUtils.extend(StateShape, mxDoubleEllipse);
2843	StateShape.prototype.outerStroke = true;
2844	StateShape.prototype.paintVertexShape = function(c, x, y, w, h)
2845	{
2846		var inset = Math.min(4, Math.min(w / 5, h / 5));
2847
2848		if (w > 0 && h > 0)
2849		{
2850			c.ellipse(x + inset, y + inset, w - 2 * inset, h - 2 * inset);
2851			c.fillAndStroke();
2852		}
2853
2854		c.setShadow(false);
2855
2856		if (this.outerStroke)
2857		{
2858			c.ellipse(x, y, w, h);
2859			c.stroke();
2860		}
2861	};
2862
2863	mxCellRenderer.registerShape('endState', StateShape);
2864
2865	function StartStateShape()
2866	{
2867		StateShape.call(this);
2868	};
2869	mxUtils.extend(StartStateShape, StateShape);
2870	StartStateShape.prototype.outerStroke = false;
2871
2872	mxCellRenderer.registerShape('startState', StartStateShape);
2873
2874	// Link shape
2875	function LinkShape()
2876	{
2877		mxArrowConnector.call(this);
2878		this.spacing = 0;
2879	};
2880	mxUtils.extend(LinkShape, mxArrowConnector);
2881	LinkShape.prototype.defaultWidth = 4;
2882
2883	LinkShape.prototype.isOpenEnded = function()
2884	{
2885		return true;
2886	};
2887
2888	LinkShape.prototype.getEdgeWidth = function()
2889	{
2890		return mxUtils.getNumber(this.style, 'width', this.defaultWidth) + Math.max(0, this.strokewidth - 1);
2891	};
2892
2893	LinkShape.prototype.isArrowRounded = function()
2894	{
2895		return this.isRounded;
2896	};
2897
2898	// Registers the link shape
2899	mxCellRenderer.registerShape('link', LinkShape);
2900
2901	// Generic arrow
2902	function FlexArrowShape()
2903	{
2904		mxArrowConnector.call(this);
2905		this.spacing = 0;
2906	};
2907	mxUtils.extend(FlexArrowShape, mxArrowConnector);
2908	FlexArrowShape.prototype.defaultWidth = 10;
2909	FlexArrowShape.prototype.defaultArrowWidth = 20;
2910
2911	FlexArrowShape.prototype.getStartArrowWidth = function()
2912	{
2913		return this.getEdgeWidth() + mxUtils.getNumber(this.style, 'startWidth', this.defaultArrowWidth);
2914	};
2915
2916	FlexArrowShape.prototype.getEndArrowWidth = function()
2917	{
2918		return this.getEdgeWidth() + mxUtils.getNumber(this.style, 'endWidth', this.defaultArrowWidth);;
2919	};
2920
2921	FlexArrowShape.prototype.getEdgeWidth = function()
2922	{
2923		return mxUtils.getNumber(this.style, 'width', this.defaultWidth) + Math.max(0, this.strokewidth - 1);
2924	};
2925
2926	// Registers the link shape
2927	mxCellRenderer.registerShape('flexArrow', FlexArrowShape);
2928
2929	// Manual Input shape
2930	function ManualInputShape()
2931	{
2932		mxActor.call(this);
2933	};
2934	mxUtils.extend(ManualInputShape, mxActor);
2935	ManualInputShape.prototype.size = 30;
2936	ManualInputShape.prototype.isRoundable = function()
2937	{
2938		return true;
2939	};
2940	ManualInputShape.prototype.redrawPath = function(c, x, y, w, h)
2941	{
2942		var s = Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)));
2943		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
2944		this.addPoints(c, [new mxPoint(0, h), new mxPoint(0, s), new mxPoint(w, 0), new mxPoint(w, h)],
2945				this.isRounded, arcSize, true);
2946		c.end();
2947	};
2948
2949	mxCellRenderer.registerShape('manualInput', ManualInputShape);
2950
2951	// Internal storage
2952	function InternalStorageShape()
2953	{
2954		mxRectangleShape.call(this);
2955	};
2956	mxUtils.extend(InternalStorageShape, mxRectangleShape);
2957	InternalStorageShape.prototype.dx = 20;
2958	InternalStorageShape.prototype.dy = 20;
2959	InternalStorageShape.prototype.isHtmlAllowed = function()
2960	{
2961		return false;
2962	};
2963	InternalStorageShape.prototype.paintForeground = function(c, x, y, w, h)
2964	{
2965		mxRectangleShape.prototype.paintForeground.apply(this, arguments);
2966		var inset = 0;
2967
2968		if (this.isRounded)
2969		{
2970			var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
2971				mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
2972			inset = Math.max(inset, Math.min(w * f, h * f));
2973		}
2974
2975		var dx = Math.max(inset, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
2976		var dy = Math.max(inset, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))));
2977
2978		c.begin();
2979		c.moveTo(x, y + dy);
2980		c.lineTo(x + w, y + dy);
2981		c.end();
2982		c.stroke();
2983
2984		c.begin();
2985		c.moveTo(x + dx, y);
2986		c.lineTo(x + dx, y + h);
2987		c.end();
2988		c.stroke();
2989	};
2990
2991	mxCellRenderer.registerShape('internalStorage', InternalStorageShape);
2992
2993	// Internal storage
2994	function CornerShape()
2995	{
2996		mxActor.call(this);
2997	};
2998	mxUtils.extend(CornerShape, mxActor);
2999	CornerShape.prototype.dx = 20;
3000	CornerShape.prototype.dy = 20;
3001
3002	// Corner
3003	CornerShape.prototype.redrawPath = function(c, x, y, w, h)
3004	{
3005		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
3006		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))));
3007
3008		var s = Math.min(w / 2, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3009		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3010		this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0), new mxPoint(w, dy), new mxPoint(dx, dy),
3011		                   new mxPoint(dx, h), new mxPoint(0, h)], this.isRounded, arcSize, true);
3012		c.end();
3013	};
3014
3015	mxCellRenderer.registerShape('corner', CornerShape);
3016
3017	// Crossbar shape
3018	function CrossbarShape()
3019	{
3020		mxActor.call(this);
3021	};
3022	mxUtils.extend(CrossbarShape, mxActor);
3023
3024	CrossbarShape.prototype.redrawPath = function(c, x, y, w, h)
3025	{
3026		c.moveTo(0, 0);
3027		c.lineTo(0, h);
3028		c.end();
3029
3030		c.moveTo(w, 0);
3031		c.lineTo(w, h);
3032		c.end();
3033
3034		c.moveTo(0, h / 2);
3035		c.lineTo(w, h / 2);
3036		c.end();
3037	};
3038
3039	mxCellRenderer.registerShape('crossbar', CrossbarShape);
3040
3041	// Internal storage
3042	function TeeShape()
3043	{
3044		mxActor.call(this);
3045	};
3046	mxUtils.extend(TeeShape, mxActor);
3047	TeeShape.prototype.dx = 20;
3048	TeeShape.prototype.dy = 20;
3049
3050	// Corner
3051	TeeShape.prototype.redrawPath = function(c, x, y, w, h)
3052	{
3053		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
3054		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))));
3055		var w2 = Math.abs(w - dx) / 2;
3056
3057		var s = Math.min(w / 2, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3058		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3059		this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0), new mxPoint(w, dy), new mxPoint((w + dx) / 2, dy),
3060		                   new mxPoint((w + dx) / 2, h), new mxPoint((w - dx) / 2, h), new mxPoint((w - dx) / 2, dy),
3061		                   new mxPoint(0, dy)], this.isRounded, arcSize, true);
3062		c.end();
3063	};
3064
3065	mxCellRenderer.registerShape('tee', TeeShape);
3066
3067	// Arrow
3068	function SingleArrowShape()
3069	{
3070		mxActor.call(this);
3071	};
3072	mxUtils.extend(SingleArrowShape, mxActor);
3073	SingleArrowShape.prototype.arrowWidth = 0.3;
3074	SingleArrowShape.prototype.arrowSize = 0.2;
3075	SingleArrowShape.prototype.redrawPath = function(c, x, y, w, h)
3076	{
3077		var aw = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowWidth', this.arrowWidth))));
3078		var as = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowSize', this.arrowSize))));
3079		var at = (h - aw) / 2;
3080		var ab = at + aw;
3081
3082		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3083		this.addPoints(c, [new mxPoint(0, at), new mxPoint(w - as, at), new mxPoint(w - as, 0), new mxPoint(w, h / 2),
3084		                   new mxPoint(w - as, h), new mxPoint(w - as, ab), new mxPoint(0, ab)],
3085		                   this.isRounded, arcSize, true);
3086		c.end();
3087	};
3088
3089	mxCellRenderer.registerShape('singleArrow', SingleArrowShape);
3090
3091	// Arrow
3092	function DoubleArrowShape()
3093	{
3094		mxActor.call(this);
3095	};
3096	mxUtils.extend(DoubleArrowShape, mxActor);
3097	DoubleArrowShape.prototype.redrawPath = function(c, x, y, w, h)
3098	{
3099		var aw = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowWidth', SingleArrowShape.prototype.arrowWidth))));
3100		var as = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowSize', SingleArrowShape.prototype.arrowSize))));
3101		var at = (h - aw) / 2;
3102		var ab = at + aw;
3103
3104		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3105		this.addPoints(c, [new mxPoint(0, h / 2), new mxPoint(as, 0), new mxPoint(as, at), new mxPoint(w - as, at),
3106		                   new mxPoint(w - as, 0), new mxPoint(w, h / 2), new mxPoint(w - as, h),
3107		                   new mxPoint(w - as, ab), new mxPoint(as, ab), new mxPoint(as, h)],
3108		                   this.isRounded, arcSize, true);
3109		c.end();
3110	};
3111
3112	mxCellRenderer.registerShape('doubleArrow', DoubleArrowShape);
3113
3114	// Data storage
3115	function DataStorageShape()
3116	{
3117		mxActor.call(this);
3118	};
3119	mxUtils.extend(DataStorageShape, mxActor);
3120	DataStorageShape.prototype.size = 0.1;
3121	DataStorageShape.prototype.fixedSize = 20;
3122	DataStorageShape.prototype.redrawPath = function(c, x, y, w, h)
3123	{
3124		var fixed = mxUtils.getValue(this.style, 'fixedSize', '0') != '0';
3125		var s = (fixed) ? Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'size', this.fixedSize)))) :
3126			w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3127
3128		c.moveTo(s, 0);
3129		c.lineTo(w, 0);
3130		c.quadTo(w - s * 2, h / 2, w, h);
3131		c.lineTo(s, h);
3132		c.quadTo(s - s * 2, h / 2, s, 0);
3133		c.close();
3134		c.end();
3135	};
3136
3137	mxCellRenderer.registerShape('dataStorage', DataStorageShape);
3138
3139	// Or
3140	function OrShape()
3141	{
3142		mxActor.call(this);
3143	};
3144	mxUtils.extend(OrShape, mxActor);
3145	OrShape.prototype.redrawPath = function(c, x, y, w, h)
3146	{
3147		c.moveTo(0, 0);
3148		c.quadTo(w, 0, w, h / 2);
3149		c.quadTo(w, h, 0, h);
3150		c.close();
3151		c.end();
3152	};
3153
3154	mxCellRenderer.registerShape('or', OrShape);
3155
3156	// Xor
3157	function XorShape()
3158	{
3159		mxActor.call(this);
3160	};
3161	mxUtils.extend(XorShape, mxActor);
3162	XorShape.prototype.redrawPath = function(c, x, y, w, h)
3163	{
3164		c.moveTo(0, 0);
3165		c.quadTo(w, 0, w, h / 2);
3166		c.quadTo(w, h, 0, h);
3167		c.quadTo(w / 2, h / 2, 0, 0);
3168		c.close();
3169		c.end();
3170	};
3171
3172	mxCellRenderer.registerShape('xor', XorShape);
3173
3174	// Loop limit
3175	function LoopLimitShape()
3176	{
3177		mxActor.call(this);
3178	};
3179	mxUtils.extend(LoopLimitShape, mxActor);
3180	LoopLimitShape.prototype.size = 20;
3181	LoopLimitShape.prototype.isRoundable = function()
3182	{
3183		return true;
3184	};
3185	LoopLimitShape.prototype.redrawPath = function(c, x, y, w, h)
3186	{
3187		var s = Math.min(w / 2, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3188		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3189		this.addPoints(c, [new mxPoint(s, 0), new mxPoint(w - s, 0), new mxPoint(w, s * 0.8), new mxPoint(w, h),
3190		                   new mxPoint(0, h), new mxPoint(0, s * 0.8)], this.isRounded, arcSize, true);
3191		c.end();
3192	};
3193
3194	mxCellRenderer.registerShape('loopLimit', LoopLimitShape);
3195
3196	// Off page connector
3197	function OffPageConnectorShape()
3198	{
3199		mxActor.call(this);
3200	};
3201	mxUtils.extend(OffPageConnectorShape, mxActor);
3202	OffPageConnectorShape.prototype.size = 3 / 8;
3203	OffPageConnectorShape.prototype.isRoundable = function()
3204	{
3205		return true;
3206	};
3207	OffPageConnectorShape.prototype.redrawPath = function(c, x, y, w, h)
3208	{
3209		var s = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3210		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
3211		this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0), new mxPoint(w, h - s), new mxPoint(w / 2, h),
3212		                   new mxPoint(0, h - s)], this.isRounded, arcSize, true);
3213		c.end();
3214	};
3215
3216	mxCellRenderer.registerShape('offPageConnector', OffPageConnectorShape);
3217
3218	// Internal storage
3219	function TapeDataShape()
3220	{
3221		mxEllipse.call(this);
3222	};
3223	mxUtils.extend(TapeDataShape, mxEllipse);
3224	TapeDataShape.prototype.paintVertexShape = function(c, x, y, w, h)
3225	{
3226		mxEllipse.prototype.paintVertexShape.apply(this, arguments);
3227
3228		c.begin();
3229		c.moveTo(x + w / 2, y + h);
3230		c.lineTo(x + w, y + h);
3231		c.end();
3232		c.stroke();
3233	};
3234
3235	mxCellRenderer.registerShape('tapeData', TapeDataShape);
3236
3237	// OrEllipseShape
3238	function OrEllipseShape()
3239	{
3240		mxEllipse.call(this);
3241	};
3242	mxUtils.extend(OrEllipseShape, mxEllipse);
3243	OrEllipseShape.prototype.paintVertexShape = function(c, x, y, w, h)
3244	{
3245		mxEllipse.prototype.paintVertexShape.apply(this, arguments);
3246
3247		c.setShadow(false);
3248		c.begin();
3249		c.moveTo(x, y + h / 2);
3250		c.lineTo(x + w, y + h / 2);
3251		c.end();
3252		c.stroke();
3253
3254		c.begin();
3255		c.moveTo(x + w / 2, y);
3256		c.lineTo(x + w / 2, y + h);
3257		c.end();
3258		c.stroke();
3259	};
3260
3261	mxCellRenderer.registerShape('orEllipse', OrEllipseShape);
3262
3263	// SumEllipseShape
3264	function SumEllipseShape()
3265	{
3266		mxEllipse.call(this);
3267	};
3268	mxUtils.extend(SumEllipseShape, mxEllipse);
3269	SumEllipseShape.prototype.paintVertexShape = function(c, x, y, w, h)
3270	{
3271		mxEllipse.prototype.paintVertexShape.apply(this, arguments);
3272		var s2 = 0.145;
3273
3274		c.setShadow(false);
3275		c.begin();
3276		c.moveTo(x + w * s2, y + h * s2);
3277		c.lineTo(x + w * (1 - s2), y + h * (1 - s2));
3278		c.end();
3279		c.stroke();
3280
3281		c.begin();
3282		c.moveTo(x + w * (1 - s2), y + h * s2);
3283		c.lineTo(x + w * s2, y + h * (1 - s2));
3284		c.end();
3285		c.stroke();
3286	};
3287
3288	mxCellRenderer.registerShape('sumEllipse', SumEllipseShape);
3289
3290	// SortShape
3291	function SortShape()
3292	{
3293		mxRhombus.call(this);
3294	};
3295	mxUtils.extend(SortShape, mxRhombus);
3296	SortShape.prototype.paintVertexShape = function(c, x, y, w, h)
3297	{
3298		mxRhombus.prototype.paintVertexShape.apply(this, arguments);
3299
3300		c.setShadow(false);
3301		c.begin();
3302		c.moveTo(x, y + h / 2);
3303		c.lineTo(x + w, y + h / 2);
3304		c.end();
3305		c.stroke();
3306	};
3307
3308	mxCellRenderer.registerShape('sortShape', SortShape);
3309
3310	// CollateShape
3311	function CollateShape()
3312	{
3313		mxEllipse.call(this);
3314	};
3315	mxUtils.extend(CollateShape, mxEllipse);
3316	CollateShape.prototype.paintVertexShape = function(c, x, y, w, h)
3317	{
3318		c.begin();
3319		c.moveTo(x, y);
3320		c.lineTo(x + w, y);
3321		c.lineTo(x + w / 2, y + h / 2);
3322		c.close();
3323		c.fillAndStroke();
3324
3325		c.begin();
3326		c.moveTo(x, y + h);
3327		c.lineTo(x + w, y + h);
3328		c.lineTo(x + w / 2, y + h / 2);
3329		c.close();
3330		c.fillAndStroke();
3331	};
3332
3333	mxCellRenderer.registerShape('collate', CollateShape);
3334
3335	// DimensionShape
3336	function DimensionShape()
3337	{
3338		mxEllipse.call(this);
3339	};
3340	mxUtils.extend(DimensionShape, mxEllipse);
3341	DimensionShape.prototype.paintVertexShape = function(c, x, y, w, h)
3342	{
3343		// Arrow size
3344		var al = 10;
3345		var cy = y + h - al / 2;
3346
3347		c.begin();
3348		c.moveTo(x, y);
3349		c.lineTo(x, y + h);
3350		c.moveTo(x, cy);
3351		c.lineTo(x + al, cy - al / 2);
3352		c.moveTo(x, cy);
3353		c.lineTo(x + al, cy + al / 2);
3354		c.moveTo(x, cy);
3355		c.lineTo(x + w, cy);
3356
3357		// Opposite side
3358		c.moveTo(x + w, y);
3359		c.lineTo(x + w, y + h);
3360		c.moveTo(x + w, cy);
3361		c.lineTo(x + w - al, cy - al / 2);
3362		c.moveTo(x + w, cy);
3363		c.lineTo(x + w - al, cy + al / 2);
3364		c.end();
3365		c.stroke();
3366	};
3367
3368	mxCellRenderer.registerShape('dimension', DimensionShape);
3369
3370	// PartialRectangleShape
3371	function PartialRectangleShape()
3372	{
3373		mxEllipse.call(this);
3374	};
3375	mxUtils.extend(PartialRectangleShape, mxEllipse);
3376	PartialRectangleShape.prototype.paintVertexShape = function(c, x, y, w, h)
3377	{
3378		if (!this.outline)
3379		{
3380			c.setStrokeColor(null);
3381		}
3382
3383		if (this.style != null)
3384		{
3385			var pointerEvents = c.pointerEvents;
3386			var events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
3387
3388			if (!events && (this.fill == null || this.fill == mxConstants.NONE))
3389			{
3390				c.pointerEvents = false;
3391			}
3392
3393			c.rect(x, y, w, h);
3394			c.fill();
3395
3396			c.pointerEvents = pointerEvents;
3397			c.setStrokeColor(this.stroke);
3398			c.begin();
3399			c.moveTo(x, y);
3400
3401			if (this.outline || mxUtils.getValue(this.style, 'top', '1') == '1')
3402			{
3403				c.lineTo(x + w, y);
3404			}
3405			else
3406			{
3407				c.moveTo(x + w, y);
3408			}
3409
3410			if (this.outline || mxUtils.getValue(this.style, 'right', '1') == '1')
3411			{
3412				c.lineTo(x + w, y + h);
3413			}
3414			else
3415			{
3416				c.moveTo(x + w, y + h);
3417			}
3418
3419			if (this.outline || mxUtils.getValue(this.style, 'bottom', '1') == '1')
3420			{
3421				c.lineTo(x, y + h);
3422			}
3423			else
3424			{
3425				c.moveTo(x, y + h);
3426			}
3427
3428			if (this.outline || mxUtils.getValue(this.style, 'left', '1') == '1')
3429			{
3430				c.lineTo(x, y);
3431			}
3432
3433			c.end();
3434			c.stroke();
3435		}
3436	};
3437
3438	mxCellRenderer.registerShape('partialRectangle', PartialRectangleShape);
3439
3440	// LineEllipseShape
3441	function LineEllipseShape()
3442	{
3443		mxEllipse.call(this);
3444	};
3445	mxUtils.extend(LineEllipseShape, mxEllipse);
3446	LineEllipseShape.prototype.paintVertexShape = function(c, x, y, w, h)
3447	{
3448		mxEllipse.prototype.paintVertexShape.apply(this, arguments);
3449
3450		c.setShadow(false);
3451		c.begin();
3452
3453		if (mxUtils.getValue(this.style, 'line') == 'vertical')
3454		{
3455			c.moveTo(x + w / 2, y);
3456			c.lineTo(x + w / 2, y + h);
3457		}
3458		else
3459		{
3460			c.moveTo(x, y + h / 2);
3461			c.lineTo(x + w, y + h / 2);
3462		}
3463
3464		c.end();
3465		c.stroke();
3466	};
3467
3468	mxCellRenderer.registerShape('lineEllipse', LineEllipseShape);
3469
3470	// Delay
3471	function DelayShape()
3472	{
3473		mxActor.call(this);
3474	};
3475	mxUtils.extend(DelayShape, mxActor);
3476	DelayShape.prototype.redrawPath = function(c, x, y, w, h)
3477	{
3478		var dx = Math.min(w, h / 2);
3479		c.moveTo(0, 0);
3480		c.lineTo(w - dx, 0);
3481		c.quadTo(w, 0, w, h / 2);
3482		c.quadTo(w, h, w - dx, h);
3483		c.lineTo(0, h);
3484		c.close();
3485		c.end();
3486	};
3487
3488	mxCellRenderer.registerShape('delay', DelayShape);
3489
3490	// Cross Shape
3491	function CrossShape()
3492	{
3493		mxActor.call(this);
3494	};
3495	mxUtils.extend(CrossShape, mxActor);
3496	CrossShape.prototype.size = 0.2;
3497	CrossShape.prototype.redrawPath = function(c, x, y, w, h)
3498	{
3499		var m = Math.min(h, w);
3500		var size = Math.max(0, Math.min(m, m * parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3501		var t = (h - size) / 2;
3502		var b = t + size;
3503		var l = (w - size) / 2;
3504		var r = l + size;
3505
3506		c.moveTo(0, t);
3507		c.lineTo(l, t);
3508		c.lineTo(l, 0);
3509		c.lineTo(r, 0);
3510		c.lineTo(r, t);
3511		c.lineTo(w, t);
3512		c.lineTo(w, b);
3513		c.lineTo(r, b);
3514		c.lineTo(r, h);
3515		c.lineTo(l, h);
3516		c.lineTo(l, b);
3517		c.lineTo(0, b);
3518		c.close();
3519		c.end();
3520	};
3521
3522	mxCellRenderer.registerShape('cross', CrossShape);
3523
3524	// Display
3525	function DisplayShape()
3526	{
3527		mxActor.call(this);
3528	};
3529	mxUtils.extend(DisplayShape, mxActor);
3530	DisplayShape.prototype.size = 0.25;
3531	DisplayShape.prototype.redrawPath = function(c, x, y, w, h)
3532	{
3533		var dx = Math.min(w, h / 2);
3534		var s = Math.min(w - dx, Math.max(0, parseFloat(mxUtils.getValue(this.style, 'size', this.size))) * w);
3535
3536		c.moveTo(0, h / 2);
3537		c.lineTo(s, 0);
3538		c.lineTo(w - dx, 0);
3539		c.quadTo(w, 0, w, h / 2);
3540		c.quadTo(w, h, w - dx, h);
3541		c.lineTo(s, h);
3542		c.close();
3543		c.end();
3544	};
3545
3546	mxCellRenderer.registerShape('display', DisplayShape);
3547
3548	//**********************************************************************************************************************************************************
3549	//Rectangle v2
3550	//**********************************************************************************************************************************************************
3551	/**
3552	* Extends mxShape.
3553	*/
3554	function mxShapeBasicRect2(bounds, fill, stroke, strokewidth)
3555	{
3556		mxShape.call(this);
3557		this.bounds = bounds;
3558		this.fill = fill;
3559		this.stroke = stroke;
3560		this.strokewidth = (strokewidth != null) ? strokewidth : 1;
3561		this.rectStyle = 'square';
3562		this.size = 10;
3563		this.absoluteCornerSize = true;
3564		this.indent = 2;
3565		this.rectOutline = 'single';
3566	};
3567
3568	/**
3569	* Extends mxShape.
3570	*/
3571	mxUtils.extend(mxShapeBasicRect2, mxActor);
3572
3573	mxShapeBasicRect2.prototype.cst = {RECT2 : 'mxgraph.basic.rect'};
3574
3575	mxShapeBasicRect2.prototype.customProperties = [
3576		{name: 'rectStyle', dispName: 'Style', type: 'enum', defVal:'square',
3577			enumList:[
3578				{val:'square', dispName:'Square'},
3579				{val:'rounded', dispName:'Round'},
3580				{val:'snip', dispName:'Snip'},
3581				{val:'invRound', dispName:'Inv. Round'},
3582				{val:'fold', dispName:'Fold'}
3583			]},
3584		{name: 'size', dispName: 'Corner Size', type: 'float', defVal:10},
3585		{name: 'absoluteCornerSize', dispName: 'Abs. Corner Size', type: 'bool', defVal:true},
3586		{name: 'indent', dispName:'Indent', type:'float', defVal:2},
3587		{name: 'rectOutline', dispName: 'Outline', type: 'enum', defVal:'single',
3588			enumList:[
3589				{val:'single', dispName:'Single'},
3590				{val:'double', dispName:'Double'},
3591				{val:'frame', dispName:'Frame'}
3592			]},
3593		{name: 'fillColor2', dispName:'Inside Fill Color', type:'color', defVal:'none'},
3594		{name: 'gradientColor2', dispName:'Inside Gradient Color', type:'color', defVal:'none'},
3595		{name: 'gradientDirection2', dispName: 'Inside Gradient Direction', type: 'enum', defVal:'south',
3596			enumList:[
3597				{val:'south', dispName:'South'},
3598				{val:'west', dispName:'West'},
3599				{val:'north', dispName:'North'},
3600				{val:'east', dispName:'East'}
3601		]},
3602		{name: 'top', dispName:'Top Line', type:'bool', defVal:true},
3603		{name: 'right', dispName:'Right', type:'bool', defVal:true},
3604		{name: 'bottom', dispName:'Bottom Line', type:'bool', defVal:true},
3605		{name: 'left', dispName:'Left ', type:'bool', defVal:true},
3606		{name: 'topLeftStyle', dispName: 'Top Left Style', type: 'enum', defVal:'default',
3607		enumList:[
3608			{val:'default', dispName:'Default'},
3609			{val:'square', dispName:'Square'},
3610			{val:'rounded', dispName:'Round'},
3611			{val:'snip', dispName:'Snip'},
3612			{val:'invRound', dispName:'Inv. Round'},
3613			{val:'fold', dispName:'Fold'}
3614		]},
3615		{name: 'topRightStyle', dispName: 'Top Right Style', type: 'enum', defVal:'default',
3616			enumList:[
3617				{val:'default', dispName:'Default'},
3618				{val:'square', dispName:'Square'},
3619				{val:'rounded', dispName:'Round'},
3620				{val:'snip', dispName:'Snip'},
3621				{val:'invRound', dispName:'Inv. Round'},
3622				{val:'fold', dispName:'Fold'}
3623		]},
3624		{name: 'bottomRightStyle', dispName: 'Bottom Right Style', type: 'enum', defVal:'default',
3625			enumList:[
3626				{val:'default', dispName:'Default'},
3627				{val:'square', dispName:'Square'},
3628				{val:'rounded', dispName:'Round'},
3629				{val:'snip', dispName:'Snip'},
3630				{val:'invRound', dispName:'Inv. Round'},
3631				{val:'fold', dispName:'Fold'}
3632		]},
3633		{name: 'bottomLeftStyle', dispName: 'Bottom Left Style', type: 'enum', defVal:'default',
3634			enumList:[
3635				{val:'default', dispName:'Default'},
3636				{val:'square', dispName:'Square'},
3637				{val:'rounded', dispName:'Round'},
3638				{val:'snip', dispName:'Snip'},
3639				{val:'invRound', dispName:'Inv. Round'},
3640				{val:'fold', dispName:'Fold'}
3641		]},
3642	];
3643
3644	/**
3645	* Function: paintVertexShape
3646	*
3647	* Paints the vertex shape.
3648	*/
3649	mxShapeBasicRect2.prototype.paintVertexShape = function(c, x, y, w, h)
3650	{
3651		c.translate(x, y);
3652		this.strictDrawShape(c, 0, 0, w, h);
3653	}
3654
3655	//
3656	mxShapeBasicRect2.prototype.strictDrawShape = function(c, x, y, w, h, os)
3657	{
3658		// read styles or optionally override them externally via "os" variable
3659		var rectStyle =	(os && os.rectStyle) ? os.rectStyle : mxUtils.getValue(this.style, 'rectStyle', this.rectStyle);
3660		var absoluteCornerSize = (os && os.absoluteCornerSize) ? os.absoluteCornerSize : mxUtils.getValue(this.style, 'absoluteCornerSize', this.absoluteCornerSize);
3661		var size =	(os && os.size) ? os.size : Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
3662		var rectOutline = (os && os.rectOutline) ? os.rectOutline : mxUtils.getValue(this.style, 'rectOutline', this.rectOutline);
3663		var indent = (os && os.indent) ? os.indent : Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'indent', this.indent))));
3664		var dashed = (os && os.dashed) ? os.dashed : mxUtils.getValue(this.style, 'dashed', false);
3665		var dashPattern = (os && os.dashPattern) ? os.dashPattern : mxUtils.getValue(this.style, 'dashPattern', null);
3666		var relIndent = (os && os.relIndent) ? os.relIndent : Math.max(0, Math.min(50, indent));
3667		var top = (os && os.top) ? os.top : mxUtils.getValue(this.style, 'top', true);
3668		var right = (os && os.right) ? os.right : mxUtils.getValue(this.style, 'right', true);
3669		var bottom = (os && os.bottom) ? os.bottom : mxUtils.getValue(this.style, 'bottom', true);
3670		var left = (os && os.left) ? os.left : mxUtils.getValue(this.style, 'left', true);
3671		var topLeftStyle = (os && os.topLeftStyle) ? os.topLeftStyle : mxUtils.getValue(this.style, 'topLeftStyle', 'default');
3672		var topRightStyle = (os && os.topRightStyle) ? os.topRightStyle : mxUtils.getValue(this.style, 'topRightStyle', 'default');
3673		var bottomRightStyle = (os && os.bottomRightStyle) ? os.bottomRightStyle : mxUtils.getValue(this.style, 'bottomRightStyle', 'default');
3674		var bottomLeftStyle = (os && os.bottomLeftStyle) ? os.bottomLeftStyle : mxUtils.getValue(this.style, 'bottomLeftStyle', 'default');
3675		var fillColor = (os && os.fillColor) ? os.fillColor : mxUtils.getValue(this.style, 'fillColor', '#ffffff');
3676		var strokeColor = (os && os.strokeColor) ? os.strokeColor : mxUtils.getValue(this.style, 'strokeColor', '#000000');
3677		var strokeWidth = (os && os.strokeWidth) ? os.strokeWidth : mxUtils.getValue(this.style, 'strokeWidth', '1');
3678		var fillColor2 = (os && os.fillColor2) ? os.fillColor2 : mxUtils.getValue(this.style, 'fillColor2', 'none');
3679		var gradientColor2 = (os && os.gradientColor2) ? os.gradientColor2 : mxUtils.getValue(this.style, 'gradientColor2', 'none');
3680		var gdir2 = (os && os.gradientDirection2) ? os.gradientDirection2 : mxUtils.getValue(this.style, 'gradientDirection2', 'south');
3681		var opacity = (os && os.opacity) ? os.opacity : mxUtils.getValue(this.style, 'opacity', '100');
3682
3683		var relSize = Math.max(0, Math.min(50, size));
3684		var sc = mxShapeBasicRect2.prototype;
3685
3686		c.setDashed(dashed);
3687
3688		if (dashPattern && dashPattern != '')
3689		{
3690			c.setDashPattern(dashPattern);
3691		}
3692
3693		c.setStrokeWidth(strokeWidth);
3694
3695		size = Math.min(h * 0.5, w * 0.5, size);
3696
3697		if (!absoluteCornerSize)
3698		{
3699			size = relSize * Math.min(w, h) / 100;
3700		}
3701
3702		size = Math.min(size, Math.min(w, h) * 0.5);
3703
3704		if (!absoluteCornerSize)
3705		{
3706			indent = Math.min(relIndent * Math.min(w, h) / 100);
3707		}
3708
3709		indent = Math.min(indent, Math.min(w, h) * 0.5 - size);
3710
3711		if ((top || right || bottom || left) && rectOutline != 'frame')
3712		{
3713
3714			//outline fill
3715			c.begin();
3716			if (!top)
3717			{
3718				c.moveTo(0,0);
3719			}
3720			else
3721			{
3722				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
3723			}
3724
3725			if (top)
3726			{
3727				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
3728			}
3729
3730			sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
3731
3732			if (right)
3733			{
3734				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3735			}
3736
3737			sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3738
3739			if (bottom)
3740			{
3741				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3742			}
3743
3744			sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3745
3746			if (left)
3747			{
3748				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
3749			}
3750
3751			sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3752			c.close();
3753			c.fill();
3754
3755			c.setShadow(false);
3756
3757			//inner fill
3758			c.setFillColor(fillColor2);
3759			var op1 = opacity;
3760			var op2 = opacity;
3761
3762			if (fillColor2 == 'none')
3763			{
3764				op1 = 0;
3765			}
3766
3767			if (gradientColor2 == 'none')
3768			{
3769				op2 = 0;
3770			}
3771
3772			c.setGradient(fillColor2, gradientColor2, 0, 0, w, h, gdir2, op1, op2);
3773
3774			c.begin();
3775
3776			if (!top)
3777			{
3778				c.moveTo(indent,0);
3779			}
3780			else
3781			{
3782				sc.moveNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3783			}
3784
3785			sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3786
3787			if (left && bottom)
3788			{
3789				sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
3790			}
3791
3792			sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
3793
3794			if (bottom && right)
3795			{
3796				sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
3797			}
3798
3799			sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
3800
3801			if (right && top)
3802			{
3803				sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
3804			}
3805
3806			sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
3807
3808			if (top && left)
3809			{
3810				sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
3811			}
3812
3813			c.fill();
3814
3815			if (fillColor == 'none')
3816			{
3817				c.begin();
3818				sc.paintFolds(c, x, y, w, h, rectStyle, topLeftStyle, topRightStyle, bottomRightStyle, bottomLeftStyle, size, top, right, bottom, left);
3819				c.stroke();
3820			}
3821		}
3822
3823		//draw all the combinations
3824		if (!top && !right && !bottom && left)
3825		{
3826
3827			if (rectOutline != 'frame')
3828			{
3829				c.begin();
3830				sc.moveSW(c, x, y, w, h, rectStyle, topLeftStyle, size, bottom);
3831				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3832
3833				if (rectOutline == 'double')
3834				{
3835					sc.moveNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3836					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3837				}
3838
3839				c.stroke();
3840			}
3841			else
3842			{
3843				c.begin();
3844				sc.moveSW(c, x, y, w, h, rectStyle, topLeftStyle, size, bottom);
3845				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3846				sc.lineNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3847				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3848				c.close();
3849				c.fillAndStroke();
3850			}
3851		}
3852		else if (!top && !right && bottom && !left)
3853		{
3854			if (rectOutline != 'frame')
3855			{
3856				c.begin();
3857				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3858				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3859
3860				if (rectOutline == 'double')
3861				{
3862					sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
3863					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
3864				}
3865
3866				c.stroke();
3867			}
3868			else
3869			{
3870				c.begin();
3871				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3872				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3873				sc.lineSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
3874				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
3875				c.close();
3876				c.fillAndStroke();
3877			}
3878		}
3879		else if (!top && !right && bottom && left)
3880		{
3881			if (rectOutline != 'frame')
3882			{
3883				c.begin();
3884				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3885				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3886				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
3887				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3888
3889				if (rectOutline == 'double')
3890				{
3891					sc.moveNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3892					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3893					sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
3894					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
3895				}
3896
3897				c.stroke();
3898			}
3899			else
3900			{
3901				c.begin();
3902				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3903				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3904				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
3905				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3906				sc.lineNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3907				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3908				sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
3909				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
3910				c.close();
3911				c.fillAndStroke();
3912			}
3913		}
3914		else if (!top && right && !bottom && !left)
3915		{
3916			if (rectOutline != 'frame')
3917			{
3918				c.begin();
3919				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3920				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3921
3922				if (rectOutline == 'double')
3923				{
3924					sc.moveSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
3925					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
3926				}
3927
3928				c.stroke();
3929			}
3930			else
3931			{
3932				c.begin();
3933				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3934				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3935				sc.lineSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
3936				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
3937				c.close();
3938				c.fillAndStroke();
3939			}
3940		}
3941		else if (!top && right && !bottom && left)
3942		{
3943			if (rectOutline != 'frame')
3944			{
3945				c.begin();
3946				sc.moveSW(c, x, y, w, h, rectStyle, topLeftStyle, size, bottom);
3947				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3948
3949				if (rectOutline == 'double')
3950				{
3951					sc.moveNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3952					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3953				}
3954
3955				c.stroke();
3956
3957				c.begin();
3958				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3959				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3960
3961				if (rectOutline == 'double')
3962				{
3963					sc.moveSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
3964					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
3965				}
3966
3967				c.stroke();
3968			}
3969			else
3970			{
3971				c.begin();
3972				sc.moveSW(c, x, y, w, h, rectStyle, topLeftStyle, size, bottom);
3973				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
3974				sc.lineNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
3975				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
3976				c.close();
3977				c.fillAndStroke();
3978
3979				c.begin();
3980				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3981				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3982				sc.lineSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
3983				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
3984				c.close();
3985				c.fillAndStroke();
3986			}
3987		}
3988		else if (!top && right && bottom && !left)
3989		{
3990			if (rectOutline != 'frame')
3991			{
3992				c.begin();
3993				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
3994				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
3995				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
3996				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
3997
3998				if (rectOutline == 'double')
3999				{
4000					sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4001					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4002					sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4003					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4004				}
4005
4006				c.stroke();
4007			}
4008			else
4009			{
4010				c.begin();
4011				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4012				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4013				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4014				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4015				sc.lineSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4016				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4017				sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4018				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4019				c.close();
4020				c.fillAndStroke();
4021			}
4022		}
4023		else if (!top && right && bottom && left)
4024		{
4025			if (rectOutline != 'frame')
4026			{
4027				c.begin();
4028				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4029				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4030				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4031				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4032				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4033				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4034
4035				if (rectOutline == 'double')
4036				{
4037					sc.moveNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
4038					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4039					sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4040					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4041					sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4042					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4043				}
4044
4045				c.stroke();
4046			}
4047			else
4048			{
4049				c.begin();
4050				sc.moveNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4051				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4052				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4053				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4054				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4055				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4056				sc.lineNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left);
4057				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4058				sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4059				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4060				sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4061				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4062				c.close();
4063				c.fillAndStroke();
4064			}
4065		}
4066		else if (top && !right && !bottom && !left)
4067		{
4068			if (rectOutline != 'frame')
4069			{
4070				c.begin();
4071				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4072				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4073
4074				if (rectOutline == 'double')
4075				{
4076					sc.moveNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4077					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4078				}
4079
4080				c.stroke();
4081			}
4082			else
4083			{
4084				c.begin();
4085				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4086				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4087				sc.lineNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4088				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4089				c.close();
4090				c.fillAndStroke();
4091			}
4092		}
4093		else if (top && !right && !bottom && left)
4094		{
4095			if (rectOutline != 'frame')
4096			{
4097				c.begin();
4098				sc.moveSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4099				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4100				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4101				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4102
4103				if (rectOutline == 'double')
4104				{
4105					sc.moveNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4106					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4107					sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4108					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4109				}
4110
4111				c.stroke();
4112			}
4113			else
4114			{
4115				c.begin();
4116				sc.moveSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4117				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4118				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4119				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4120				sc.lineNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4121				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4122				sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4123				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4124				c.close();
4125				c.fillAndStroke();
4126			}
4127		}
4128		else if (top && !right && bottom && !left)
4129		{
4130			if (rectOutline != 'frame')
4131			{
4132				c.begin();
4133				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4134				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4135
4136				if (rectOutline == 'double')
4137				{
4138					sc.moveNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4139					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4140				}
4141
4142				c.stroke();
4143
4144				c.begin();
4145				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4146				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4147
4148				if (rectOutline == 'double')
4149				{
4150					sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4151					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4152				}
4153
4154				c.stroke();
4155			}
4156			else
4157			{
4158				c.begin();
4159				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4160				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4161				sc.lineNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4162				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4163				c.close();
4164				c.fillAndStroke();
4165
4166				c.begin();
4167				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4168				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4169				sc.lineSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4170				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4171				c.close();
4172				c.fillAndStroke();
4173			}
4174		}
4175		else if (top && !right && bottom && left)
4176		{
4177			if (rectOutline != 'frame')
4178			{
4179				c.begin();
4180				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4181				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4182				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4183				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4184				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4185				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4186
4187				if (rectOutline == 'double')
4188				{
4189					sc.moveNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4190					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4191					sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4192					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4193					sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4194					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4195				}
4196
4197				c.stroke();
4198			}
4199			else
4200			{
4201				c.begin();
4202				sc.moveSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4203				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4204				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4205				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4206				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4207				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4208				sc.lineNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right);
4209				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4210				sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4211				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4212				sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4213				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4214				c.close();
4215				c.fillAndStroke();
4216			}
4217		}
4218		else if (top && right && !bottom && !left)
4219		{
4220			if (rectOutline != 'frame')
4221			{
4222				c.begin();
4223				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4224				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4225				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4226				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4227
4228				if (rectOutline == 'double')
4229				{
4230					sc.moveSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
4231					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4232					sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4233					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4234				}
4235
4236				c.stroke();
4237			}
4238			else
4239			{
4240				c.begin();
4241				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4242				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4243				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4244				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4245				sc.lineSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
4246				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4247				sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4248				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4249				c.close();
4250				c.fillAndStroke();
4251			}
4252		}
4253		else if (top && right && !bottom && left)
4254		{
4255			if (rectOutline != 'frame')
4256			{
4257				c.begin();
4258				sc.moveSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4259				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4260				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4261				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4262				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4263				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4264
4265				if (rectOutline == 'double')
4266				{
4267					sc.moveSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
4268					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4269					sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4270					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4271					sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4272					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4273				}
4274
4275				c.stroke();
4276			}
4277			else
4278			{
4279				c.begin();
4280				sc.moveSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4281				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4282				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4283				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4284				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4285				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4286				sc.lineSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom);
4287				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4288				sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4289				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4290				sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4291				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4292				c.close();
4293				c.fillAndStroke();
4294			}
4295		}
4296		else if (top && right && bottom && !left)
4297		{
4298			if (rectOutline != 'frame')
4299			{
4300				c.begin();
4301				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4302				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4303				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4304				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4305				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4306				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4307
4308				if (rectOutline == 'double')
4309				{
4310					sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4311					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4312					sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4313					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4314					sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4315					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4316				}
4317
4318				c.stroke();
4319			}
4320			else
4321			{
4322				c.begin();
4323				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4324				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4325				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4326				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4327				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4328				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4329				sc.lineSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4330				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4331				sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4332				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4333				sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4334				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4335				c.close();
4336				c.fillAndStroke();
4337			}
4338		}
4339		else if (top && right && bottom && left)
4340		{
4341			if (rectOutline != 'frame')
4342			{
4343				c.begin();
4344				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4345				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4346				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4347				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4348				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4349				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4350				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4351				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4352				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4353				c.close();
4354
4355				if (rectOutline == 'double')
4356				{
4357					sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4358					sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4359					sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4360					sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4361					sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4362					sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4363					sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4364					sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4365					sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4366					c.close();
4367				}
4368
4369				c.stroke();
4370			}
4371			else
4372			{
4373				c.begin();
4374				sc.moveNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4375				sc.paintNW(c, x, y, w, h, rectStyle, topLeftStyle, size, left);
4376				sc.paintTop(c, x, y, w, h, rectStyle, topRightStyle, size, right);
4377				sc.paintNE(c, x, y, w, h, rectStyle, topRightStyle, size, top);
4378				sc.paintRight(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom);
4379				sc.paintSE(c, x, y, w, h, rectStyle, bottomRightStyle, size, right);
4380				sc.paintBottom(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left);
4381				sc.paintSW(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom);
4382				sc.paintLeft(c, x, y, w, h, rectStyle, topLeftStyle, size, top);
4383				c.close();
4384				sc.moveSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left);
4385				sc.paintSWInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom);
4386				sc.paintBottomInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom);
4387				sc.paintSEInner(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent);
4388				sc.paintRightInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right);
4389				sc.paintNEInner(c, x, y, w, h, rectStyle, topRightStyle, size, indent);
4390				sc.paintTopInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top);
4391				sc.paintNWInner(c, x, y, w, h, rectStyle, topLeftStyle, size, indent);
4392				sc.paintLeftInner(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left);
4393				c.close();
4394				c.fillAndStroke();
4395			}
4396		}
4397
4398		c.begin();
4399		sc.paintFolds(c, x, y, w, h, rectStyle, topLeftStyle, topRightStyle, bottomRightStyle, bottomLeftStyle, size, top, right, bottom, left);
4400		c.stroke();
4401	};
4402
4403	mxShapeBasicRect2.prototype.moveNW = function(c, x, y, w, h, rectStyle, topLeftStyle, size, left)
4404	{
4405		if((topLeftStyle == 'square' || (topLeftStyle == 'default' && rectStyle == 'square' )) || !left)
4406		{
4407			c.moveTo(0, 0);
4408		}
4409		else
4410		{
4411			c.moveTo(0, size);
4412		}
4413	};
4414
4415	mxShapeBasicRect2.prototype.moveNE = function(c, x, y, w, h, rectStyle, topRightStyle, size, top)
4416	{
4417		if((topRightStyle == 'square' || (topRightStyle == 'default' && rectStyle == 'square' )) || !top)
4418		{
4419			c.moveTo(w, 0);
4420		}
4421		else
4422		{
4423			c.moveTo(w - size, 0);
4424		}
4425	};
4426
4427	mxShapeBasicRect2.prototype.moveSE = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, right)
4428	{
4429		if((bottomRightStyle == 'square' || (bottomRightStyle == 'default' && rectStyle == 'square' )) || !right)
4430		{
4431			c.moveTo(w, h);
4432		}
4433		else
4434		{
4435			c.moveTo(w, h - size);
4436		}
4437	};
4438
4439	mxShapeBasicRect2.prototype.moveSW = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom)
4440	{
4441		if((bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' )) || !bottom)
4442		{
4443			c.moveTo(0, h);
4444		}
4445		else
4446		{
4447			c.moveTo(size, h);
4448		}
4449	};
4450
4451	mxShapeBasicRect2.prototype.paintNW = function(c, x, y, w, h, rectStyle, topLeftStyle, size, left)
4452	{
4453		if (!left)
4454		{
4455			c.lineTo(0, 0);
4456		}
4457		else if((topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4458				(topLeftStyle == 'invRound' || (topLeftStyle == 'default' && rectStyle == 'invRound' )) )
4459		{
4460			var inv = 0;
4461
4462			if (topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' ))
4463			{
4464				inv = 1;
4465			}
4466
4467			c.arcTo(size, size, 0, 0, inv, size, 0);
4468		}
4469		else if((topLeftStyle == 'snip' || (topLeftStyle == 'default' && rectStyle == 'snip' )) ||
4470				(topLeftStyle == 'fold' || (topLeftStyle == 'default' && rectStyle == 'fold' )))
4471		{
4472			c.lineTo(size, 0);
4473		}
4474	};
4475
4476	mxShapeBasicRect2.prototype.paintTop = function(c, x, y, w, h, rectStyle, topRightStyle, size, right)
4477	{
4478		if((topRightStyle == 'square' || (topRightStyle == 'default' && rectStyle == 'square' )) || !right)
4479		{
4480			c.lineTo(w, 0);
4481		}
4482		else
4483		{
4484			c.lineTo(w - size, 0);
4485		}
4486	};
4487
4488	mxShapeBasicRect2.prototype.paintNE = function(c, x, y, w, h, rectStyle, topRightStyle, size, top)
4489	{
4490		if (!top)
4491		{
4492			c.lineTo(w, 0);
4493		}
4494		else if((topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' )) ||
4495				(topRightStyle == 'invRound' || (topRightStyle == 'default' && rectStyle == 'invRound' )) )
4496		{
4497			var inv = 0;
4498
4499			if (topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' ))
4500			{
4501				inv = 1;
4502			}
4503
4504			c.arcTo(size, size, 0, 0, inv, w, size);
4505		}
4506		else if((topRightStyle == 'snip' || (topRightStyle == 'default' && rectStyle == 'snip' )) ||
4507				(topRightStyle == 'fold' || (topRightStyle == 'default' && rectStyle == 'fold' )))
4508		{
4509			c.lineTo(w, size);
4510		}
4511	};
4512
4513	mxShapeBasicRect2.prototype.paintRight = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, bottom)
4514	{
4515		if((bottomRightStyle == 'square' || (bottomRightStyle == 'default' && rectStyle == 'square' )) || !bottom)
4516		{
4517			c.lineTo(w, h);
4518		}
4519		else
4520		{
4521			c.lineTo(w, h - size);
4522		}
4523	};
4524
4525	mxShapeBasicRect2.prototype.paintLeft = function(c, x, y, w, h, rectStyle, topLeftStyle, size, top)
4526	{
4527		if((topLeftStyle == 'square' || (topLeftStyle == 'default' && rectStyle == 'square' )) || !top)
4528		{
4529			c.lineTo(0, 0);
4530		}
4531		else
4532		{
4533			c.lineTo(0, size);
4534		}
4535	};
4536
4537	mxShapeBasicRect2.prototype.paintSE = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, right)
4538	{
4539		if (!right)
4540		{
4541			c.lineTo(w, h);
4542		}
4543		else if((bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' )) ||
4544				(bottomRightStyle == 'invRound' || (bottomRightStyle == 'default' && rectStyle == 'invRound' )) )
4545		{
4546			var inv = 0;
4547
4548			if (bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' ))
4549			{
4550				inv = 1;
4551			}
4552
4553			c.arcTo(size, size, 0, 0, inv, w - size, h);
4554		}
4555		else if((bottomRightStyle == 'snip' || (bottomRightStyle == 'default' && rectStyle == 'snip' )) ||
4556				(bottomRightStyle == 'fold' || (bottomRightStyle == 'default' && rectStyle == 'fold' )))
4557		{
4558			c.lineTo(w - size, h);
4559		}
4560	};
4561
4562	mxShapeBasicRect2.prototype.paintBottom = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, left)
4563	{
4564		if((bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' )) || !left)
4565		{
4566			c.lineTo(0, h);
4567		}
4568		else
4569		{
4570			c.lineTo(size, h);
4571		}
4572	};
4573
4574	mxShapeBasicRect2.prototype.paintSW = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, bottom)
4575	{
4576		if (!bottom)
4577		{
4578			c.lineTo(0, h);
4579		}
4580		else if((bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4581				(bottomLeftStyle == 'invRound' || (bottomLeftStyle == 'default' && rectStyle == 'invRound' )) )
4582		{
4583			var inv = 0;
4584
4585			if (bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' ))
4586			{
4587				inv = 1;
4588			}
4589
4590			c.arcTo(size, size, 0, 0, inv, 0, h - size);
4591		}
4592		else if((bottomLeftStyle == 'snip' || (bottomLeftStyle == 'default' && rectStyle == 'snip' )) ||
4593				(bottomLeftStyle == 'fold' || (bottomLeftStyle == 'default' && rectStyle == 'fold' )))
4594		{
4595			c.lineTo(0, h - size);
4596		}
4597	};
4598
4599	mxShapeBasicRect2.prototype.paintNWInner = function(c, x, y, w, h, rectStyle, topLeftStyle, size, indent)
4600	{
4601		if(topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' ))
4602		{
4603			c.arcTo(size - indent * 0.5, size - indent * 0.5, 0, 0, 0, indent, indent * 0.5 + size);
4604		}
4605		else if(topLeftStyle == 'invRound' || (topLeftStyle == 'default' && rectStyle == 'invRound' ))
4606		{
4607			c.arcTo(size + indent, size + indent, 0, 0, 1, indent, indent + size);
4608		}
4609		else if(topLeftStyle == 'snip' || (topLeftStyle == 'default' && rectStyle == 'snip' ))
4610		{
4611			c.lineTo(indent, indent * 0.5 + size);
4612		}
4613		else if(topLeftStyle == 'fold' || (topLeftStyle == 'default' && rectStyle == 'fold' ))
4614		{
4615			c.lineTo(indent + size, indent + size);
4616			c.lineTo(indent, indent + size);
4617		}
4618	};
4619
4620	mxShapeBasicRect2.prototype.paintTopInner = function(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, left, top)
4621	{
4622		if (!left && !top)
4623		{
4624			c.lineTo(0, 0);
4625		}
4626		else if (!left && top)
4627		{
4628			c.lineTo(0, indent);
4629		}
4630		else if (left && !top)
4631		{
4632			c.lineTo(indent, 0);
4633		}
4634		else if (!left)
4635		{
4636			c.lineTo(0, indent);
4637		}
4638		else if(topLeftStyle == 'square' || (topLeftStyle == 'default' && rectStyle == 'square' ))
4639		{
4640			c.lineTo(indent, indent);
4641		}
4642		else if((topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4643				(topLeftStyle == 'snip' || (topLeftStyle == 'default' && rectStyle == 'snip' )))
4644		{
4645			c.lineTo(size + indent * 0.5, indent);
4646		}
4647		else
4648		{
4649			c.lineTo(size + indent, indent);
4650		}
4651	};
4652
4653	mxShapeBasicRect2.prototype.paintNEInner = function(c, x, y, w, h, rectStyle, topRightStyle, size, indent)
4654	{
4655		if(topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' ))
4656		{
4657			c.arcTo(size - indent * 0.5, size - indent * 0.5, 0, 0, 0, w - size - indent * 0.5, indent);
4658		}
4659		else if(topRightStyle == 'invRound' || (topRightStyle == 'default' && rectStyle == 'invRound' ))
4660		{
4661			c.arcTo(size + indent, size + indent, 0, 0, 1, w - size - indent, indent);
4662		}
4663		else if(topRightStyle == 'snip' || (topRightStyle == 'default' && rectStyle == 'snip' ))
4664		{
4665			c.lineTo(w - size - indent * 0.5, indent);
4666		}
4667		else if(topRightStyle == 'fold' || (topRightStyle == 'default' && rectStyle == 'fold' ))
4668		{
4669			c.lineTo(w - size - indent, size + indent);
4670			c.lineTo(w - size - indent, indent);
4671		}
4672	};
4673
4674	mxShapeBasicRect2.prototype.paintRightInner = function(c, x, y, w, h, rectStyle, topRightStyle, size, indent, top, right)
4675	{
4676		if (!top && !right)
4677		{
4678			c.lineTo(w, 0);
4679		}
4680		else if (!top && right)
4681		{
4682			c.lineTo(w - indent, 0);
4683		}
4684		else if (top && !right)
4685		{
4686			c.lineTo(w, indent);
4687		}
4688		else if (!top)
4689		{
4690			c.lineTo(w - indent, 0);
4691		}
4692		else if(topRightStyle == 'square' || (topRightStyle == 'default' && rectStyle == 'square' ))
4693		{
4694			c.lineTo(w - indent, indent);
4695		}
4696		else if((topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' )) ||
4697				(topRightStyle == 'snip' || (topRightStyle == 'default' && rectStyle == 'snip' )))
4698		{
4699			c.lineTo(w - indent, size + indent * 0.5);
4700		}
4701		else
4702		{
4703			c.lineTo(w - indent, size + indent);
4704		}
4705	};
4706
4707	mxShapeBasicRect2.prototype.paintLeftInner = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom, left)
4708	{
4709		if (!bottom && !left)
4710		{
4711			c.lineTo(0, h);
4712		}
4713		else if (!bottom && left)
4714		{
4715			c.lineTo(indent, h);
4716		}
4717		else if (bottom && !left)
4718		{
4719			c.lineTo(0, h - indent);
4720		}
4721		else if (!bottom)
4722		{
4723			c.lineTo(indent, h);
4724		}
4725		else if(bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' ))
4726		{
4727			c.lineTo(indent, h - indent);
4728		}
4729		else if((bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4730				(bottomLeftStyle == 'snip' || (bottomLeftStyle == 'default' && rectStyle == 'snip' )))
4731		{
4732			c.lineTo(indent, h - size - indent * 0.5);
4733		}
4734		else
4735		{
4736			c.lineTo(indent, h - size - indent);
4737		}
4738	};
4739
4740	mxShapeBasicRect2.prototype.paintSEInner = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent)
4741	{
4742		if(bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' ))
4743		{
4744			c.arcTo(size - indent * 0.5, size - indent * 0.5, 0, 0, 0, w - indent, h - size - indent * 0.5);
4745		}
4746		else if(bottomRightStyle == 'invRound' || (bottomRightStyle == 'default' && rectStyle == 'invRound' ))
4747		{
4748			c.arcTo(size + indent, size + indent, 0, 0, 1, w - indent, h - size - indent);
4749		}
4750		else if(bottomRightStyle == 'snip' || (bottomRightStyle == 'default' && rectStyle == 'snip' ))
4751		{
4752			c.lineTo(w - indent, h - size - indent * 0.5);
4753		}
4754		else if(bottomRightStyle == 'fold' || (bottomRightStyle == 'default' && rectStyle == 'fold' ))
4755		{
4756			c.lineTo(w - size - indent, h - size - indent);
4757			c.lineTo(w - indent, h - size - indent);
4758		}
4759	};
4760
4761	mxShapeBasicRect2.prototype.paintBottomInner = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, right, bottom)
4762	{
4763		if (!right && !bottom)
4764		{
4765			c.lineTo(w, h);
4766		}
4767		else if (!right && bottom)
4768		{
4769			c.lineTo(w, h - indent);
4770		}
4771		else if (right && !bottom)
4772		{
4773			c.lineTo(w - indent, h);
4774		}
4775		else if((bottomRightStyle == 'square' || (bottomRightStyle == 'default' && rectStyle == 'square' )) || !right)
4776		{
4777			c.lineTo(w - indent, h - indent);
4778		}
4779		else if((bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' )) ||
4780				(bottomRightStyle == 'snip' || (bottomRightStyle == 'default' && rectStyle == 'snip' )))
4781		{
4782			c.lineTo(w - size - indent * 0.5, h - indent);
4783		}
4784		else
4785		{
4786			c.lineTo(w - size - indent, h - indent);
4787		}
4788	};
4789
4790	mxShapeBasicRect2.prototype.paintSWInner = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, bottom)
4791	{
4792		if (!bottom)
4793		{
4794			c.lineTo(indent, h);
4795		}
4796		else if(bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' ))
4797		{
4798			c.lineTo(indent, h - indent);
4799		}
4800		else if(bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' ))
4801		{
4802			c.arcTo(size - indent * 0.5, size - indent * 0.5, 0, 0, 0, size + indent * 0.5, h - indent);
4803		}
4804		else if(bottomLeftStyle == 'invRound' || (bottomLeftStyle == 'default' && rectStyle == 'invRound' ))
4805		{
4806			c.arcTo(size + indent, size + indent, 0, 0, 1, size + indent, h - indent);
4807		}
4808		else if(bottomLeftStyle == 'snip' || (bottomLeftStyle == 'default' && rectStyle == 'snip' ))
4809		{
4810			c.lineTo(size + indent * 0.5, h - indent);
4811		}
4812		else if(bottomLeftStyle == 'fold' || (bottomLeftStyle == 'default' && rectStyle == 'fold' ))
4813		{
4814			c.lineTo(indent + size, h - size - indent);
4815			c.lineTo(indent + size, h - indent);
4816		}
4817	};
4818
4819	mxShapeBasicRect2.prototype.moveSWInner = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left)
4820	{
4821		if (!left)
4822		{
4823			c.moveTo(0, h - indent);
4824		}
4825		else if(bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' ))
4826		{
4827			c.moveTo(indent, h - indent);
4828		}
4829		else if((bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4830				(bottomLeftStyle == 'snip' || (bottomLeftStyle == 'default' && rectStyle == 'snip' )))
4831		{
4832			c.moveTo(indent, h - size - indent * 0.5);
4833		}
4834		else if((bottomLeftStyle == 'invRound' || (bottomLeftStyle == 'default' && rectStyle == 'invRound' )) ||
4835				(bottomLeftStyle == 'fold' || (bottomLeftStyle == 'default' && rectStyle == 'fold' )))
4836		{
4837			c.moveTo(indent, h - size - indent);
4838		}
4839	};
4840
4841	mxShapeBasicRect2.prototype.lineSWInner = function(c, x, y, w, h, rectStyle, bottomLeftStyle, size, indent, left)
4842	{
4843		if (!left)
4844		{
4845			c.lineTo(0, h - indent);
4846		}
4847		else if(bottomLeftStyle == 'square' || (bottomLeftStyle == 'default' && rectStyle == 'square' ))
4848		{
4849			c.lineTo(indent, h - indent);
4850		}
4851		else if((bottomLeftStyle == 'rounded' || (bottomLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4852				(bottomLeftStyle == 'snip' || (bottomLeftStyle == 'default' && rectStyle == 'snip' )))
4853		{
4854			c.lineTo(indent, h - size - indent * 0.5);
4855		}
4856		else if((bottomLeftStyle == 'invRound' || (bottomLeftStyle == 'default' && rectStyle == 'invRound' )) ||
4857				(bottomLeftStyle == 'fold' || (bottomLeftStyle == 'default' && rectStyle == 'fold' )))
4858		{
4859				c.lineTo(indent, h - size - indent);
4860		}
4861	};
4862
4863	mxShapeBasicRect2.prototype.moveSEInner = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom)
4864	{
4865		if (!bottom)
4866		{
4867			c.moveTo(w - indent, h);
4868		}
4869		else if(bottomRightStyle == 'square' || (bottomRightStyle == 'default' && rectStyle == 'square' ))
4870		{
4871			c.moveTo(w - indent, h - indent);
4872		}
4873		else if((bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' )) ||
4874				(bottomRightStyle == 'snip' || (bottomRightStyle == 'default' && rectStyle == 'snip' )))
4875		{
4876			c.moveTo(w - indent, h - size - indent * 0.5);
4877		}
4878		else if((bottomRightStyle == 'invRound' || (bottomRightStyle == 'default' && rectStyle == 'invRound' )) ||
4879				(bottomRightStyle == 'fold' || (bottomRightStyle == 'default' && rectStyle == 'fold' )))
4880		{
4881			c.moveTo(w - indent, h - size - indent);
4882		}
4883	};
4884
4885	mxShapeBasicRect2.prototype.lineSEInner = function(c, x, y, w, h, rectStyle, bottomRightStyle, size, indent, bottom)
4886	{
4887		if (!bottom)
4888		{
4889			c.lineTo(w - indent, h);
4890		}
4891		else if(bottomRightStyle == 'square' || (bottomRightStyle == 'default' && rectStyle == 'square' ))
4892		{
4893			c.lineTo(w - indent, h - indent);
4894		}
4895		else if((bottomRightStyle == 'rounded' || (bottomRightStyle == 'default' && rectStyle == 'rounded' )) ||
4896				(bottomRightStyle == 'snip' || (bottomRightStyle == 'default' && rectStyle == 'snip' )))
4897		{
4898			c.lineTo(w - indent, h - size - indent * 0.5);
4899		}
4900		else if((bottomRightStyle == 'invRound' || (bottomRightStyle == 'default' && rectStyle == 'invRound' )) ||
4901				(bottomRightStyle == 'fold' || (bottomRightStyle == 'default' && rectStyle == 'fold' )))
4902		{
4903			c.lineTo(w - indent, h - size - indent);
4904		}
4905	};
4906
4907	mxShapeBasicRect2.prototype.moveNEInner = function(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right)
4908	{
4909		if (!right)
4910		{
4911			c.moveTo(w, indent);
4912		}
4913		else if((topRightStyle == 'square' || (topRightStyle == 'default' && rectStyle == 'square' )) || right)
4914		{
4915			c.moveTo(w - indent, indent);
4916		}
4917		else if((topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' )) ||
4918				(topRightStyle == 'snip' || (topRightStyle == 'default' && rectStyle == 'snip' )))
4919		{
4920			c.moveTo(w - indent, size + indent * 0.5);
4921		}
4922		else if((topRightStyle == 'invRound' || (topRightStyle == 'default' && rectStyle == 'invRound' )) ||
4923				(topRightStyle == 'fold' || (topRightStyle == 'default' && rectStyle == 'fold' )))
4924		{
4925			c.moveTo(w - indent, size + indent);
4926		}
4927	};
4928
4929	mxShapeBasicRect2.prototype.lineNEInner = function(c, x, y, w, h, rectStyle, topRightStyle, size, indent, right)
4930	{
4931		if (!right)
4932		{
4933			c.lineTo(w, indent);
4934		}
4935		else if((topRightStyle == 'square' || (topRightStyle == 'default' && rectStyle == 'square' )) || right)
4936		{
4937			c.lineTo(w - indent, indent);
4938		}
4939		else if((topRightStyle == 'rounded' || (topRightStyle == 'default' && rectStyle == 'rounded' )) ||
4940				(topRightStyle == 'snip' || (topRightStyle == 'default' && rectStyle == 'snip' )))
4941		{
4942			c.lineTo(w - indent, size + indent * 0.5);
4943		}
4944		else if((topRightStyle == 'invRound' || (topRightStyle == 'default' && rectStyle == 'invRound' )) ||
4945				(topRightStyle == 'fold' || (topRightStyle == 'default' && rectStyle == 'fold' )))
4946		{
4947			c.lineTo(w - indent, size + indent);
4948		}
4949	};
4950
4951	mxShapeBasicRect2.prototype.moveNWInner = function(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left)
4952	{
4953		if (!top && !left)
4954		{
4955			c.moveTo(0, 0);
4956		}
4957		else if (!top && left)
4958		{
4959			c.moveTo(indent, 0);
4960		}
4961		else if (top && !left)
4962		{
4963			c.moveTo(0, indent);
4964		}
4965		else if(topLeftStyle == 'square' || (topLeftStyle == 'default' && rectStyle == 'square' ))
4966		{
4967			c.moveTo(indent, indent);
4968		}
4969		else if((topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' )) ||
4970				(topLeftStyle == 'snip' || (topLeftStyle == 'default' && rectStyle == 'snip' )))
4971		{
4972			c.moveTo(indent, size + indent * 0.5);
4973		}
4974		else if((topLeftStyle == 'invRound' || (topLeftStyle == 'default' && rectStyle == 'invRound' )) ||
4975				(topLeftStyle == 'fold' || (topLeftStyle == 'default' && rectStyle == 'fold' )))
4976		{
4977			c.moveTo(indent, size + indent);
4978		}
4979	};
4980
4981	mxShapeBasicRect2.prototype.lineNWInner = function(c, x, y, w, h, rectStyle, topLeftStyle, size, indent, top, left)
4982	{
4983		if (!top && !left)
4984		{
4985			c.lineTo(0, 0);
4986		}
4987		else if (!top && left)
4988		{
4989			c.lineTo(indent, 0);
4990		}
4991		else if (top && !left)
4992		{
4993			c.lineTo(0, indent);
4994		}
4995		else if(topLeftStyle == 'square' || (topLeftStyle == 'default' && rectStyle == 'square' ))
4996		{
4997			c.lineTo(indent, indent);
4998		}
4999		else if((topLeftStyle == 'rounded' || (topLeftStyle == 'default' && rectStyle == 'rounded' )) ||
5000				(topLeftStyle == 'snip' || (topLeftStyle == 'default' && rectStyle == 'snip' )))
5001		{
5002			c.lineTo(indent, size + indent * 0.5);
5003		}
5004		else if((topLeftStyle == 'invRound' || (topLeftStyle == 'default' && rectStyle == 'invRound' )) ||
5005				(topLeftStyle == 'fold' || (topLeftStyle == 'default' && rectStyle == 'fold' )))
5006		{
5007			c.lineTo(indent, size + indent);
5008		}
5009	};
5010
5011	mxShapeBasicRect2.prototype.paintFolds = function(c, x, y, w, h, rectStyle, topLeftStyle, topRightStyle, bottomRightStyle, bottomLeftStyle, size, top, right, bottom, left)
5012	{
5013		if (rectStyle == 'fold' || topLeftStyle == 'fold' || topRightStyle == 'fold' || bottomRightStyle == 'fold' || bottomLeftStyle == 'fold')
5014		{
5015			if ((topLeftStyle == 'fold' || (topLeftStyle == 'default' && rectStyle == 'fold' )) && (top && left))
5016			{
5017				c.moveTo(0, size);
5018				c.lineTo(size, size);
5019				c.lineTo(size, 0);
5020			}
5021
5022			if ((topRightStyle == 'fold' || (topRightStyle == 'default' && rectStyle == 'fold' )) && (top && right))
5023			{
5024				c.moveTo(w - size, 0);
5025				c.lineTo(w - size, size);
5026				c.lineTo(w, size);
5027			}
5028
5029			if ((bottomRightStyle == 'fold' || (bottomRightStyle == 'default' && rectStyle == 'fold' )) && (bottom && right))
5030			{
5031				c.moveTo(w - size, h);
5032				c.lineTo(w - size, h - size);
5033				c.lineTo(w, h - size);
5034			}
5035
5036			if ((bottomLeftStyle == 'fold' || (bottomLeftStyle == 'default' && rectStyle == 'fold' )) && (bottom && left))
5037			{
5038				c.moveTo(0, h - size);
5039				c.lineTo(size, h - size);
5040				c.lineTo(size, h);
5041			}
5042		}
5043	};
5044
5045	mxCellRenderer.registerShape(mxShapeBasicRect2.prototype.cst.RECT2, mxShapeBasicRect2);
5046
5047	mxShapeBasicRect2.prototype.constraints = null;
5048
5049	// FilledEdge shape
5050	function FilledEdge()
5051	{
5052		mxConnector.call(this);
5053	};
5054	mxUtils.extend(FilledEdge, mxConnector);
5055
5056	FilledEdge.prototype.origPaintEdgeShape = FilledEdge.prototype.paintEdgeShape;
5057	FilledEdge.prototype.paintEdgeShape = function(c, pts, rounded)
5058	{
5059		// Markers modify incoming points array
5060		var temp = [];
5061
5062		for (var i = 0; i < pts.length; i++)
5063		{
5064			temp.push(mxUtils.clone(pts[i]));
5065		}
5066
5067		// paintEdgeShape resets dashed to false
5068		var dashed = c.state.dashed;
5069		var fixDash = c.state.fixDash;
5070		FilledEdge.prototype.origPaintEdgeShape.apply(this, [c, temp, rounded]);
5071
5072		if (c.state.strokeWidth >= 3)
5073		{
5074			var fillClr = mxUtils.getValue(this.style, 'fillColor', null);
5075
5076			if (fillClr != null)
5077			{
5078				c.setStrokeColor(fillClr);
5079				c.setStrokeWidth(c.state.strokeWidth - 2);
5080				c.setDashed(dashed, fixDash);
5081
5082				FilledEdge.prototype.origPaintEdgeShape.apply(this, [c, pts, rounded]);
5083			}
5084		}
5085	};
5086
5087	// Registers the link shape
5088	mxCellRenderer.registerShape('filledEdge', FilledEdge);
5089
5090	// Implements custom colors for shapes
5091	if (typeof StyleFormatPanel !== 'undefined')
5092	{
5093		(function()
5094		{
5095			var styleFormatPanelGetCustomColors = StyleFormatPanel.prototype.getCustomColors;
5096
5097			StyleFormatPanel.prototype.getCustomColors = function()
5098			{
5099				var ss = this.format.getSelectionState();
5100				var result = styleFormatPanelGetCustomColors.apply(this, arguments);
5101
5102				if (ss.style.shape == 'umlFrame')
5103				{
5104					result.push({title: mxResources.get('laneColor'), key: 'swimlaneFillColor', defaultValue: '#ffffff'});
5105				}
5106
5107				return result;
5108			};
5109		})();
5110	}
5111
5112	// Registers and defines the custom marker
5113	mxMarker.addMarker('dash', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5114	{
5115		var nx = unitX * (size + sw + 1);
5116		var ny = unitY * (size + sw + 1);
5117
5118		return function()
5119		{
5120			c.begin();
5121			c.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2);
5122			c.lineTo(pe.x + ny / 2 - 3 * nx / 2, pe.y - 3 * ny / 2 - nx / 2);
5123			c.stroke();
5124		};
5125	});
5126
5127	// Registers and defines the custom marker
5128	mxMarker.addMarker('box', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5129	{
5130		var nx = unitX * (size + sw + 1);
5131		var ny = unitY * (size + sw + 1);
5132		var px = pe.x + nx / 2;
5133		var py = pe.y + ny / 2;
5134
5135		pe.x -= nx;
5136		pe.y -= ny;
5137
5138		return function()
5139		{
5140			c.begin();
5141			c.moveTo(px - nx / 2 - ny / 2, py - ny / 2 + nx / 2);
5142			c.lineTo(px - nx / 2 + ny / 2, py - ny / 2 - nx / 2);
5143			c.lineTo(px + ny / 2 - 3 * nx / 2, py - 3 * ny / 2 - nx / 2);
5144			c.lineTo(px - ny / 2 - 3 * nx / 2, py - 3 * ny / 2 + nx / 2);
5145			c.close();
5146
5147			if (filled)
5148			{
5149				c.fillAndStroke();
5150			}
5151			else
5152			{
5153				c.stroke();
5154			}
5155		};
5156	});
5157
5158	// Registers and defines the custom marker
5159	mxMarker.addMarker('cross', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5160	{
5161		var nx = unitX * (size + sw + 1);
5162		var ny = unitY * (size + sw + 1);
5163
5164		return function()
5165		{
5166			c.begin();
5167			c.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2);
5168			c.lineTo(pe.x + ny / 2 - 3 * nx / 2, pe.y - 3 * ny / 2 - nx / 2);
5169			c.moveTo(pe.x - nx / 2 + ny / 2, pe.y - ny / 2 - nx / 2);
5170			c.lineTo(pe.x - ny / 2 - 3 * nx / 2, pe.y - 3 * ny / 2 + nx / 2);
5171			c.stroke();
5172		};
5173	});
5174
5175	function circleMarker(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5176	{
5177		var a = size / 2;
5178		var size = size + sw;
5179
5180		var pt = pe.clone();
5181
5182		pe.x -= unitX * (2 * size + sw);
5183		pe.y -= unitY * (2 * size + sw);
5184
5185		unitX = unitX * (size + sw);
5186		unitY = unitY * (size + sw);
5187
5188		return function()
5189		{
5190			c.ellipse(pt.x - unitX - size, pt.y - unitY - size, 2 * size, 2 * size);
5191
5192			if (filled)
5193			{
5194				c.fillAndStroke();
5195			}
5196			else
5197			{
5198				c.stroke();
5199			}
5200		};
5201	};
5202
5203	mxMarker.addMarker('circle', circleMarker);
5204	mxMarker.addMarker('circlePlus', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5205	{
5206		var pt = pe.clone();
5207		var fn = circleMarker.apply(this, arguments);
5208		var nx = unitX * (size + 2 * sw); // (size + sw + 1);
5209		var ny = unitY * (size + 2 * sw); //(size + sw + 1);
5210
5211		return function()
5212		{
5213			fn.apply(this, arguments);
5214
5215			c.begin();
5216			c.moveTo(pt.x - unitX * (sw), pt.y - unitY * (sw));
5217			c.lineTo(pt.x - 2 * nx + unitX * (sw), pt.y - 2 * ny + unitY * (sw));
5218			c.moveTo(pt.x - nx - ny + unitY * sw, pt.y - ny + nx - unitX * sw);
5219			c.lineTo(pt.x + ny - nx - unitY * sw, pt.y - ny - nx + unitX * sw);
5220			c.stroke();
5221		};
5222	});
5223
5224	// Registers and defines the custom marker
5225	mxMarker.addMarker('halfCircle', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5226	{
5227		var nx = unitX * (size + sw + 1);
5228		var ny = unitY * (size + sw + 1);
5229		var pt = pe.clone();
5230
5231		pe.x -= nx;
5232		pe.y -= ny;
5233
5234		return function()
5235		{
5236			c.begin();
5237			c.moveTo(pt.x - ny, pt.y + nx);
5238			c.quadTo(pe.x - ny, pe.y + nx, pe.x, pe.y);
5239			c.quadTo(pe.x + ny, pe.y - nx, pt.x + ny, pt.y - nx);
5240			c.stroke();
5241		};
5242	});
5243
5244	mxMarker.addMarker('async', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5245	{
5246		// The angle of the forward facing arrow sides against the x axis is
5247		// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
5248		// only half the strokewidth is processed ).
5249		var endOffsetX = unitX * sw * 1.118;
5250		var endOffsetY = unitY * sw * 1.118;
5251
5252		unitX = unitX * (size + sw);
5253		unitY = unitY * (size + sw);
5254
5255		var pt = pe.clone();
5256		pt.x -= endOffsetX;
5257		pt.y -= endOffsetY;
5258
5259		var f = 1;
5260		pe.x += -unitX * f - endOffsetX;
5261		pe.y += -unitY * f - endOffsetY;
5262
5263		return function()
5264		{
5265			c.begin();
5266			c.moveTo(pt.x, pt.y);
5267
5268			if (source)
5269			{
5270				c.lineTo(pt.x - unitX - unitY / 2, pt.y - unitY + unitX / 2);
5271			}
5272			else
5273			{
5274				c.lineTo(pt.x + unitY / 2 - unitX, pt.y - unitY - unitX / 2);
5275			}
5276
5277			c.lineTo(pt.x - unitX, pt.y - unitY);
5278			c.close();
5279
5280			if (filled)
5281			{
5282				c.fillAndStroke();
5283			}
5284			else
5285			{
5286				c.stroke();
5287			}
5288		};
5289	});
5290
5291	function createOpenAsyncArrow(widthFactor)
5292	{
5293		widthFactor = (widthFactor != null) ? widthFactor : 2;
5294
5295		return function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
5296		{
5297			unitX = unitX * (size + sw);
5298			unitY = unitY * (size + sw);
5299
5300			var pt = pe.clone();
5301
5302			return function()
5303			{
5304				c.begin();
5305				c.moveTo(pt.x, pt.y);
5306
5307				if (source)
5308				{
5309					c.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
5310				}
5311				else
5312				{
5313					c.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
5314				}
5315
5316				c.stroke();
5317			};
5318		}
5319	};
5320
5321	mxMarker.addMarker('openAsync', createOpenAsyncArrow(2));
5322
5323	function arrow(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
5324	{
5325		// The angle of the forward facing arrow sides against the x axis is
5326		// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
5327		// only half the strokewidth is processed ).
5328		var endOffsetX = unitX * sw * 1.118;
5329		var endOffsetY = unitY * sw * 1.118;
5330
5331		unitX = unitX * (size + sw);
5332		unitY = unitY * (size + sw);
5333
5334		var pt = pe.clone();
5335		pt.x -= endOffsetX;
5336		pt.y -= endOffsetY;
5337
5338		var f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
5339		pe.x += -unitX * f - endOffsetX;
5340		pe.y += -unitY * f - endOffsetY;
5341
5342		return function()
5343		{
5344			canvas.begin();
5345			canvas.moveTo(pt.x, pt.y);
5346			canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
5347
5348			if (type == mxConstants.ARROW_CLASSIC || type == mxConstants.ARROW_CLASSIC_THIN)
5349			{
5350				canvas.lineTo(pt.x - unitX * 3 / 4, pt.y - unitY * 3 / 4);
5351			}
5352
5353			canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
5354			canvas.close();
5355
5356			if (filled)
5357			{
5358				canvas.fillAndStroke();
5359			}
5360			else
5361			{
5362				canvas.stroke();
5363			}
5364		};
5365	}
5366
5367	// Handlers are only added if mxVertexHandler is defined (ie. not in embedded graph)
5368	if (typeof mxVertexHandler !== 'undefined')
5369	{
5370		function createHandle(state, keys, getPositionFn, setPositionFn, ignoreGrid, redrawEdges, executeFn)
5371		{
5372			var handle = new mxHandle(state, null, mxVertexHandler.prototype.secondaryHandleImage);
5373
5374			handle.execute = function(me)
5375			{
5376				for (var i = 0; i < keys.length; i++)
5377				{
5378					this.copyStyle(keys[i]);
5379				}
5380
5381				if (executeFn)
5382				{
5383					executeFn(me);
5384				}
5385			};
5386
5387			handle.getPosition = getPositionFn;
5388			handle.setPosition = setPositionFn;
5389			handle.ignoreGrid = (ignoreGrid != null) ? ignoreGrid : true;
5390
5391			// Overridden to update connected edges
5392			if (redrawEdges)
5393			{
5394				var positionChanged = handle.positionChanged;
5395
5396				handle.positionChanged = function()
5397				{
5398					positionChanged.apply(this, arguments);
5399
5400					// Redraws connected edges TODO: Include child edges
5401					state.view.invalidate(this.state.cell);
5402					state.view.validate();
5403				};
5404			}
5405
5406			return handle;
5407		};
5408
5409		function createArcHandle(state, yOffset)
5410		{
5411			return createHandle(state, [mxConstants.STYLE_ARCSIZE], function(bounds)
5412			{
5413				var tmp = (yOffset != null) ? yOffset : bounds.height / 8;
5414
5415				if (mxUtils.getValue(state.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
5416				{
5417					var arcSize = mxUtils.getValue(state.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
5418
5419					return new mxPoint(bounds.x + bounds.width - Math.min(bounds.width / 2, arcSize), bounds.y + tmp);
5420				}
5421				else
5422				{
5423					var arcSize = Math.max(0, parseFloat(mxUtils.getValue(state.style,
5424						mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100))) / 100;
5425
5426					return new mxPoint(bounds.x + bounds.width - Math.min(Math.max(bounds.width / 2, bounds.height / 2),
5427						Math.min(bounds.width, bounds.height) * arcSize), bounds.y + tmp);
5428				}
5429			}, function(bounds, pt, me)
5430			{
5431				if (mxUtils.getValue(state.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
5432				{
5433					this.state.style[mxConstants.STYLE_ARCSIZE] = Math.round(Math.max(0, Math.min(bounds.width,
5434						(bounds.x + bounds.width - pt.x) * 2)));
5435				}
5436				else
5437				{
5438					var f = Math.min(50, Math.max(0, (bounds.width - pt.x + bounds.x) * 100 /
5439						Math.min(bounds.width, bounds.height)));
5440					this.state.style[mxConstants.STYLE_ARCSIZE] = Math.round(f);
5441				}
5442			});
5443		}
5444
5445		function createArcHandleFunction()
5446		{
5447			return function(state)
5448			{
5449				var handles = [];
5450
5451				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5452				{
5453					handles.push(createArcHandle(state));
5454				}
5455
5456				return handles;
5457			};
5458		};
5459
5460		function createTrapezoidHandleFunction(max, defaultValue, fixedDefaultValue)
5461		{
5462			max = (max != null) ? max : 0.5;
5463
5464			return function(state)
5465			{
5466				var handles = [createHandle(state, ['size'], function(bounds)
5467				{
5468					var fixed = (fixedDefaultValue != null) ? mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0' : null;
5469					var size = Math.max(0, parseFloat(mxUtils.getValue(this.state.style, 'size', (fixed) ? fixedDefaultValue : defaultValue)));
5470
5471					return new mxPoint(bounds.x + Math.min(bounds.width * 0.75 * max, size * ((fixed) ? 0.75 : bounds.width * 0.75)), bounds.y + bounds.height / 4);
5472				}, function(bounds, pt)
5473				{
5474					var fixed = (fixedDefaultValue != null) ? mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0' : null;
5475					var size = (fixed) ? (pt.x - bounds.x) : Math.max(0, Math.min(max, (pt.x - bounds.x) / bounds.width * 0.75));
5476
5477					this.state.style['size'] = size;
5478				}, false, true)];
5479
5480				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5481				{
5482					handles.push(createArcHandle(state));
5483				}
5484
5485				return handles;
5486			};
5487		};
5488
5489		function createDisplayHandleFunction(defaultValue, allowArcHandle, max, redrawEdges, fixedDefaultValue)
5490		{
5491			max = (max != null) ? max : 0.5;
5492
5493			return function(state)
5494			{
5495				var handles = [createHandle(state, ['size'], function(bounds)
5496				{
5497					var fixed = (fixedDefaultValue != null) ? mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0' : null;
5498					var size = parseFloat(mxUtils.getValue(this.state.style, 'size', (fixed) ? fixedDefaultValue : defaultValue));
5499
5500					return new mxPoint(bounds.x + Math.max(0, Math.min(bounds.width * 0.5, size * ((fixed) ? 1 : bounds.width))), bounds.getCenterY());
5501				}, function(bounds, pt, me)
5502				{
5503					var fixed = (fixedDefaultValue != null) ? mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0' : null;
5504					var size = (fixed) ? (pt.x - bounds.x) : Math.max(0, Math.min(max, (pt.x - bounds.x) / bounds.width));
5505
5506					this.state.style['size'] = size;
5507				}, false, redrawEdges)];
5508
5509				if (allowArcHandle && mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5510				{
5511					handles.push(createArcHandle(state));
5512				}
5513
5514				return handles;
5515			};
5516		};
5517
5518		function createCubeHandleFunction(factor, defaultValue, allowArcHandle)
5519		{
5520			return function(state)
5521			{
5522				var handles = [createHandle(state, ['size'], function(bounds)
5523				{
5524					var size = Math.max(0, Math.min(bounds.width, Math.min(bounds.height, parseFloat(
5525						mxUtils.getValue(this.state.style, 'size', defaultValue))))) * factor;
5526
5527					return new mxPoint(bounds.x + size, bounds.y + size);
5528				}, function(bounds, pt)
5529				{
5530					this.state.style['size'] = Math.round(Math.max(0, Math.min(Math.min(bounds.width, pt.x - bounds.x),
5531							Math.min(bounds.height, pt.y - bounds.y))) / factor);
5532				}, false)];
5533
5534				if (allowArcHandle && mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5535				{
5536					handles.push(createArcHandle(state));
5537				}
5538
5539				return handles;
5540			};
5541		};
5542
5543		function createCylinderHandleFunction(defaultValue)
5544		{
5545			return function(state)
5546			{
5547				return [createHandle(state, ['size'], function(bounds)
5548						{
5549							var size = Math.max(0, Math.min(bounds.height * 0.5, parseFloat(mxUtils.getValue(this.state.style, 'size', defaultValue))));
5550
5551							return new mxPoint(bounds.x, bounds.y + size);
5552						}, function(bounds, pt)
5553						{
5554							this.state.style['size'] = Math.max(0, pt.y - bounds.y);
5555						}, true)];
5556			}
5557		};
5558
5559		function createArrowHandleFunction(maxSize)
5560		{
5561			return function(state)
5562			{
5563				return [createHandle(state, ['arrowWidth', 'arrowSize'], function(bounds)
5564				{
5565					var aw = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'arrowWidth', SingleArrowShape.prototype.arrowWidth)));
5566					var as = Math.max(0, Math.min(maxSize, mxUtils.getValue(this.state.style, 'arrowSize', SingleArrowShape.prototype.arrowSize)));
5567
5568					return new mxPoint(bounds.x + (1 - as) * bounds.width, bounds.y + (1 - aw) * bounds.height / 2);
5569				}, function(bounds, pt)
5570				{
5571					this.state.style['arrowWidth'] = Math.max(0, Math.min(1, Math.abs(bounds.y + bounds.height / 2 - pt.y) / bounds.height * 2));
5572					this.state.style['arrowSize'] = Math.max(0, Math.min(maxSize, (bounds.x + bounds.width - pt.x) / (bounds.width)));
5573				})];
5574			};
5575		};
5576
5577		function createEdgeHandle(state, keys, start, getPosition, setPosition)
5578		{
5579			return createHandle(state, keys, function(bounds)
5580			{
5581				var pts = state.absolutePoints;
5582				var n = pts.length - 1;
5583
5584				var tr = state.view.translate;
5585				var s = state.view.scale;
5586
5587				var p0 = (start) ? pts[0] : pts[n];
5588				var p1 = (start) ? pts[1] : pts[n - 1];
5589				var dx = (start) ? p1.x - p0.x : p1.x - p0.x;
5590				var dy = (start) ? p1.y - p0.y : p1.y - p0.y;
5591
5592				var dist = Math.sqrt(dx * dx + dy * dy);
5593
5594				var pt = getPosition.call(this, dist, dx / dist, dy / dist, p0, p1);
5595
5596				return new mxPoint(pt.x / s - tr.x, pt.y / s - tr.y);
5597			}, function(bounds, pt, me)
5598			{
5599				var pts = state.absolutePoints;
5600				var n = pts.length - 1;
5601
5602				var tr = state.view.translate;
5603				var s = state.view.scale;
5604
5605				var p0 = (start) ? pts[0] : pts[n];
5606				var p1 = (start) ? pts[1] : pts[n - 1];
5607				var dx = (start) ? p1.x - p0.x : p1.x - p0.x;
5608				var dy = (start) ? p1.y - p0.y : p1.y - p0.y;
5609
5610				var dist = Math.sqrt(dx * dx + dy * dy);
5611				pt.x = (pt.x + tr.x) * s;
5612				pt.y = (pt.y + tr.y) * s;
5613
5614				setPosition.call(this, dist, dx / dist, dy / dist, p0, p1, pt, me);
5615			});
5616		};
5617
5618		function createEdgeWidthHandle(state, start, spacing)
5619		{
5620			return createEdgeHandle(state, ['width'], start, function(dist, nx, ny, p0, p1)
5621			{
5622				var w = state.shape.getEdgeWidth() * state.view.scale + spacing;
5623
5624				return new mxPoint(p0.x + nx * dist / 4 + ny * w / 2, p0.y + ny * dist / 4 - nx * w / 2);
5625			}, function(dist, nx, ny, p0, p1, pt)
5626			{
5627				var w = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, p1.x, p1.y, pt.x, pt.y));
5628				state.style['width'] = Math.round(w * 2) / state.view.scale - spacing;
5629			});
5630		};
5631
5632		function ptLineDistance(x1, y1, x2, y2, x0, y0)
5633		{
5634			return Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
5635		}
5636
5637		var handleFactory = {
5638			'link': function(state)
5639			{
5640				var spacing = 10;
5641
5642				return [createEdgeWidthHandle(state, true, spacing), createEdgeWidthHandle(state, false, spacing)];
5643			},
5644			'flexArrow': function(state)
5645			{
5646				// Do not use state.shape.startSize/endSize since it is cached
5647				var tol = state.view.graph.gridSize / state.view.scale;
5648				var handles = [];
5649
5650				if (mxUtils.getValue(state.style, mxConstants.STYLE_STARTARROW, mxConstants.NONE) != mxConstants.NONE)
5651				{
5652					handles.push(createEdgeHandle(state, ['width', mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE], true, function(dist, nx, ny, p0, p1)
5653					{
5654						var w = (state.shape.getEdgeWidth() - state.shape.strokewidth) * state.view.scale;
5655						var l = mxUtils.getNumber(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.ARROW_SIZE / 5) * 3 * state.view.scale;
5656
5657						return new mxPoint(p0.x + nx * (l + state.shape.strokewidth * state.view.scale) + ny * w / 2,
5658							p0.y + ny * (l + state.shape.strokewidth * state.view.scale) - nx * w / 2);
5659					}, function(dist, nx, ny, p0, p1, pt, me)
5660					{
5661						var w = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, p1.x, p1.y, pt.x, pt.y));
5662						var l = mxUtils.ptLineDist(p0.x, p0.y, p0.x + ny, p0.y - nx, pt.x, pt.y);
5663
5664						state.style[mxConstants.STYLE_STARTSIZE] = Math.round((l - state.shape.strokewidth) * 100 / 3) / 100 / state.view.scale;
5665						state.style['width'] = Math.round(w * 2) / state.view.scale;
5666
5667						// Applies to opposite side
5668						if (mxEvent.isControlDown(me.getEvent()))
5669						{
5670							state.style[mxConstants.STYLE_ENDSIZE] = state.style[mxConstants.STYLE_STARTSIZE];
5671						}
5672
5673						// Snaps to end geometry
5674						if (!mxEvent.isAltDown(me.getEvent()))
5675						{
5676							if (Math.abs(parseFloat(state.style[mxConstants.STYLE_STARTSIZE]) - parseFloat(state.style[mxConstants.STYLE_ENDSIZE])) < tol / 6)
5677							{
5678								state.style[mxConstants.STYLE_STARTSIZE] = state.style[mxConstants.STYLE_ENDSIZE];
5679							}
5680						}
5681					}));
5682
5683					handles.push(createEdgeHandle(state, ['startWidth', 'endWidth', mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE], true, function(dist, nx, ny, p0, p1)
5684					{
5685						var w = (state.shape.getStartArrowWidth() - state.shape.strokewidth) * state.view.scale;
5686						var l = mxUtils.getNumber(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.ARROW_SIZE / 5) * 3 * state.view.scale;
5687
5688						return new mxPoint(p0.x + nx * (l + state.shape.strokewidth * state.view.scale) + ny * w / 2,
5689							p0.y + ny * (l + state.shape.strokewidth * state.view.scale) - nx * w / 2);
5690					}, function(dist, nx, ny, p0, p1, pt, me)
5691					{
5692						var w = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, p1.x, p1.y, pt.x, pt.y));
5693						var l = mxUtils.ptLineDist(p0.x, p0.y, p0.x + ny, p0.y - nx, pt.x, pt.y);
5694
5695						state.style[mxConstants.STYLE_STARTSIZE] = Math.round((l - state.shape.strokewidth) * 100 / 3) / 100 / state.view.scale;
5696						state.style['startWidth'] = Math.max(0, Math.round(w * 2) - state.shape.getEdgeWidth()) / state.view.scale;
5697
5698						// Applies to opposite side
5699						if (mxEvent.isControlDown(me.getEvent()))
5700						{
5701							state.style[mxConstants.STYLE_ENDSIZE] = state.style[mxConstants.STYLE_STARTSIZE];
5702							state.style['endWidth'] = state.style['startWidth'];
5703						}
5704
5705						// Snaps to endWidth
5706						if (!mxEvent.isAltDown(me.getEvent()))
5707						{
5708							if (Math.abs(parseFloat(state.style[mxConstants.STYLE_STARTSIZE]) - parseFloat(state.style[mxConstants.STYLE_ENDSIZE])) < tol / 6)
5709							{
5710								state.style[mxConstants.STYLE_STARTSIZE] = state.style[mxConstants.STYLE_ENDSIZE];
5711							}
5712
5713							if (Math.abs(parseFloat(state.style['startWidth']) - parseFloat(state.style['endWidth'])) < tol)
5714							{
5715								state.style['startWidth'] = state.style['endWidth'];
5716							}
5717						}
5718					}));
5719				}
5720
5721				if (mxUtils.getValue(state.style, mxConstants.STYLE_ENDARROW, mxConstants.NONE) != mxConstants.NONE)
5722				{
5723					handles.push(createEdgeHandle(state, ['width', mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE], false, function(dist, nx, ny, p0, p1)
5724					{
5725						var w = (state.shape.getEdgeWidth() - state.shape.strokewidth) * state.view.scale;
5726						var l = mxUtils.getNumber(state.style, mxConstants.STYLE_ENDSIZE, mxConstants.ARROW_SIZE / 5) * 3 * state.view.scale;
5727
5728						return new mxPoint(p0.x + nx * (l + state.shape.strokewidth * state.view.scale) - ny * w / 2,
5729							p0.y + ny * (l + state.shape.strokewidth * state.view.scale) + nx * w / 2);
5730					}, function(dist, nx, ny, p0, p1, pt, me)
5731					{
5732						var w = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, p1.x, p1.y, pt.x, pt.y));
5733						var l = mxUtils.ptLineDist(p0.x, p0.y, p0.x + ny, p0.y - nx, pt.x, pt.y);
5734
5735						state.style[mxConstants.STYLE_ENDSIZE] = Math.round((l - state.shape.strokewidth) * 100 / 3) / 100 / state.view.scale;
5736						state.style['width'] = Math.round(w * 2) / state.view.scale;
5737
5738						// Applies to opposite side
5739						if (mxEvent.isControlDown(me.getEvent()))
5740						{
5741							state.style[mxConstants.STYLE_STARTSIZE] = state.style[mxConstants.STYLE_ENDSIZE];
5742						}
5743
5744						// Snaps to start geometry
5745						if (!mxEvent.isAltDown(me.getEvent()))
5746						{
5747							if (Math.abs(parseFloat(state.style[mxConstants.STYLE_ENDSIZE]) - parseFloat(state.style[mxConstants.STYLE_STARTSIZE])) < tol / 6)
5748							{
5749								state.style[mxConstants.STYLE_ENDSIZE] = state.style[mxConstants.STYLE_STARTSIZE];
5750							}
5751						}
5752					}));
5753
5754					handles.push(createEdgeHandle(state, ['startWidth', 'endWidth', mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE], false, function(dist, nx, ny, p0, p1)
5755					{
5756						var w = (state.shape.getEndArrowWidth() - state.shape.strokewidth) * state.view.scale;
5757						var l = mxUtils.getNumber(state.style, mxConstants.STYLE_ENDSIZE, mxConstants.ARROW_SIZE / 5) * 3 * state.view.scale;
5758
5759						return new mxPoint(p0.x + nx * (l + state.shape.strokewidth * state.view.scale) - ny * w / 2,
5760							p0.y + ny * (l + state.shape.strokewidth * state.view.scale) + nx * w / 2);
5761					}, function(dist, nx, ny, p0, p1, pt, me)
5762					{
5763						var w = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, p1.x, p1.y, pt.x, pt.y));
5764						var l = mxUtils.ptLineDist(p0.x, p0.y, p0.x + ny, p0.y - nx, pt.x, pt.y);
5765
5766						state.style[mxConstants.STYLE_ENDSIZE] = Math.round((l - state.shape.strokewidth) * 100 / 3) / 100 / state.view.scale;
5767						state.style['endWidth'] = Math.max(0, Math.round(w * 2) - state.shape.getEdgeWidth()) / state.view.scale;
5768
5769						// Applies to opposite side
5770						if (mxEvent.isControlDown(me.getEvent()))
5771						{
5772							state.style[mxConstants.STYLE_STARTSIZE] = state.style[mxConstants.STYLE_ENDSIZE];
5773							state.style['startWidth'] = state.style['endWidth'];
5774						}
5775
5776						// Snaps to start geometry
5777						if (!mxEvent.isAltDown(me.getEvent()))
5778						{
5779							if (Math.abs(parseFloat(state.style[mxConstants.STYLE_ENDSIZE]) - parseFloat(state.style[mxConstants.STYLE_STARTSIZE])) < tol / 6)
5780							{
5781								state.style[mxConstants.STYLE_ENDSIZE] = state.style[mxConstants.STYLE_STARTSIZE];
5782							}
5783
5784							if (Math.abs(parseFloat(state.style['endWidth']) - parseFloat(state.style['startWidth'])) < tol)
5785							{
5786								state.style['endWidth'] = state.style['startWidth'];
5787							}
5788						}
5789					}));
5790				}
5791
5792				return handles;
5793			},
5794			'swimlane': function(state)
5795			{
5796				var handles = [];
5797
5798				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED))
5799				{
5800					var size = parseFloat(mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
5801					handles.push(createArcHandle(state, size / 2));
5802				}
5803
5804				// Start size handle must be last item in handles for hover to work in tables (see mouse event handler in Graph)
5805				handles.push(createHandle(state, [mxConstants.STYLE_STARTSIZE], function(bounds)
5806				{
5807					var size = parseFloat(mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
5808
5809					if (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, 1) == 1)
5810					{
5811						return new mxPoint(bounds.getCenterX(), bounds.y + Math.max(0, Math.min(bounds.height, size)));
5812					}
5813					else
5814					{
5815						return new mxPoint(bounds.x + Math.max(0, Math.min(bounds.width, size)), bounds.getCenterY());
5816					}
5817				}, function(bounds, pt)
5818				{
5819					state.style[mxConstants.STYLE_STARTSIZE] =
5820						(mxUtils.getValue(this.state.style, mxConstants.STYLE_HORIZONTAL, 1) == 1) ?
5821							Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y))) :
5822							Math.round(Math.max(0, Math.min(bounds.width, pt.x - bounds.x)));
5823				}, false, null, function(me)
5824				{
5825					if (mxEvent.isControlDown(me.getEvent()))
5826					{
5827						var graph = state.view.graph;
5828
5829						if (graph.isTableRow(state.cell) || graph.isTableCell(state.cell))
5830						{
5831							var dir = graph.getSwimlaneDirection(state.style);
5832							var parent = graph.model.getParent(state.cell);
5833							var cells = graph.model.getChildCells(parent, true);
5834							var temp = [];
5835
5836							for (var i = 0; i < cells.length; i++)
5837							{
5838								// Finds siblings with the same direction and to set start size
5839								if (cells[i] != state.cell && graph.isSwimlane(cells[i]) &&
5840									graph.getSwimlaneDirection(graph.getCurrentCellStyle(
5841									cells[i])) == dir)
5842								{
5843									temp.push(cells[i]);
5844								}
5845							}
5846
5847							graph.setCellStyles(mxConstants.STYLE_STARTSIZE,
5848								state.style[mxConstants.STYLE_STARTSIZE], temp);
5849						}
5850					}
5851				}));
5852
5853				return handles;
5854			},
5855			'label': createArcHandleFunction(),
5856			'ext': createArcHandleFunction(),
5857			'rectangle': createArcHandleFunction(),
5858			'triangle': createArcHandleFunction(),
5859			'rhombus': createArcHandleFunction(),
5860			'umlLifeline': function(state)
5861			{
5862				return [createHandle(state, ['size'], function(bounds)
5863				{
5864					var size = Math.max(0, Math.min(bounds.height, parseFloat(mxUtils.getValue(this.state.style, 'size', UmlLifeline.prototype.size))));
5865
5866					return new mxPoint(bounds.getCenterX(), bounds.y + size);
5867				}, function(bounds, pt)
5868				{
5869					this.state.style['size'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)));
5870				}, false)];
5871			},
5872			'umlFrame': function(state)
5873			{
5874				var handles = [createHandle(state, ['width', 'height'], function(bounds)
5875				{
5876					var w0 = Math.max(UmlFrame.prototype.corner, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'width', UmlFrame.prototype.width)));
5877					var h0 = Math.max(UmlFrame.prototype.corner * 1.5, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'height', UmlFrame.prototype.height)));
5878
5879					return new mxPoint(bounds.x + w0, bounds.y + h0);
5880				}, function(bounds, pt)
5881				{
5882					this.state.style['width'] = Math.round(Math.max(UmlFrame.prototype.corner, Math.min(bounds.width, pt.x - bounds.x)));
5883					this.state.style['height'] = Math.round(Math.max(UmlFrame.prototype.corner * 1.5, Math.min(bounds.height, pt.y - bounds.y)));
5884				}, false)];
5885
5886				return handles;
5887			},
5888			'process': function(state)
5889			{
5890				var handles = [createHandle(state, ['size'], function(bounds)
5891				{
5892
5893					var fixed = mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0';
5894					var size = parseFloat(mxUtils.getValue(this.state.style, 'size', ProcessShape.prototype.size));
5895
5896					return (fixed) ? new mxPoint(bounds.x + size, bounds.y + bounds.height / 4) : new mxPoint(bounds.x + bounds.width * size, bounds.y + bounds.height / 4);
5897				}, function(bounds, pt)
5898				{
5899					var fixed = mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0';
5900					var size = (fixed) ? Math.max(0, Math.min(bounds.width * 0.5, (pt.x - bounds.x))) : Math.max(0, Math.min(0.5, (pt.x - bounds.x) / bounds.width));
5901					this.state.style['size'] = size;
5902				}, false)];
5903
5904				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5905				{
5906					handles.push(createArcHandle(state));
5907				}
5908
5909				return handles;
5910			},
5911			'cross': function(state)
5912			{
5913				return [createHandle(state, ['size'], function(bounds)
5914				{
5915					var m = Math.min(bounds.width, bounds.height);
5916					var size = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'size', CrossShape.prototype.size))) * m / 2;
5917
5918					return new mxPoint(bounds.getCenterX() - size, bounds.getCenterY() - size);
5919				}, function(bounds, pt)
5920				{
5921					var m = Math.min(bounds.width, bounds.height);
5922					this.state.style['size'] = Math.max(0, Math.min(1, Math.min((Math.max(0, bounds.getCenterY() - pt.y) / m) * 2,
5923							(Math.max(0, bounds.getCenterX() - pt.x) / m) * 2)));
5924				})];
5925			},
5926			'note': function(state)
5927			{
5928				return [createHandle(state, ['size'], function(bounds)
5929				{
5930					var size = Math.max(0, Math.min(bounds.width, Math.min(bounds.height, parseFloat(
5931						mxUtils.getValue(this.state.style, 'size', NoteShape.prototype.size)))));
5932
5933					return new mxPoint(bounds.x + bounds.width - size, bounds.y + size);
5934				}, function(bounds, pt)
5935				{
5936					this.state.style['size'] = Math.round(Math.max(0, Math.min(Math.min(bounds.width, bounds.x + bounds.width - pt.x),
5937							Math.min(bounds.height, pt.y - bounds.y))));
5938				})];
5939			},
5940			'note2': function(state)
5941			{
5942				return [createHandle(state, ['size'], function(bounds)
5943				{
5944					var size = Math.max(0, Math.min(bounds.width, Math.min(bounds.height, parseFloat(
5945						mxUtils.getValue(this.state.style, 'size', NoteShape2.prototype.size)))));
5946
5947					return new mxPoint(bounds.x + bounds.width - size, bounds.y + size);
5948				}, function(bounds, pt)
5949				{
5950					this.state.style['size'] = Math.round(Math.max(0, Math.min(Math.min(bounds.width, bounds.x + bounds.width - pt.x),
5951							Math.min(bounds.height, pt.y - bounds.y))));
5952				})];
5953			},
5954			'manualInput': function(state)
5955			{
5956				var handles = [createHandle(state, ['size'], function(bounds)
5957				{
5958					var size = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'size', ManualInputShape.prototype.size)));
5959
5960					return new mxPoint(bounds.x + bounds.width / 4, bounds.y + size * 3 / 4);
5961				}, function(bounds, pt)
5962				{
5963					this.state.style['size'] = Math.round(Math.max(0, Math.min(bounds.height, (pt.y - bounds.y) * 4 / 3)));
5964				}, false)];
5965
5966				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
5967				{
5968					handles.push(createArcHandle(state));
5969				}
5970
5971				return handles;
5972			},
5973			'dataStorage': function(state)
5974			{
5975				return [createHandle(state, ['size'], function(bounds)
5976				{
5977					var fixed = mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0';
5978					var size = parseFloat(mxUtils.getValue(this.state.style, 'size', (fixed) ? DataStorageShape.prototype.fixedSize : DataStorageShape.prototype.size));
5979
5980					return new mxPoint(bounds.x + bounds.width - size * ((fixed) ? 1 : bounds.width), bounds.getCenterY());
5981				}, function(bounds, pt)
5982				{
5983					var fixed = mxUtils.getValue(this.state.style, 'fixedSize', '0') != '0';
5984					var size = (fixed) ? Math.max(0, Math.min(bounds.width, (bounds.x + bounds.width - pt.x))) : Math.max(0, Math.min(1, (bounds.x + bounds.width - pt.x) / bounds.width));
5985
5986					this.state.style['size'] = size;
5987				}, false)];
5988			},
5989			'callout': function(state)
5990			{
5991				var handles = [createHandle(state, ['size', 'position'], function(bounds)
5992				{
5993					var size = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'size', CalloutShape.prototype.size)));
5994					var position = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'position', CalloutShape.prototype.position)));
5995					var base = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'base', CalloutShape.prototype.base)));
5996
5997					return new mxPoint(bounds.x + position * bounds.width, bounds.y + bounds.height - size);
5998				}, function(bounds, pt)
5999				{
6000					var base = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'base', CalloutShape.prototype.base)));
6001					this.state.style['size'] = Math.round(Math.max(0, Math.min(bounds.height, bounds.y + bounds.height - pt.y)));
6002					this.state.style['position'] = Math.round(Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width)) * 100) / 100;
6003				}, false), createHandle(state, ['position2'], function(bounds)
6004				{
6005					var position2 = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'position2', CalloutShape.prototype.position2)));
6006
6007					return new mxPoint(bounds.x + position2 * bounds.width, bounds.y + bounds.height);
6008				}, function(bounds, pt)
6009				{
6010					this.state.style['position2'] = Math.round(Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width)) * 100) / 100;
6011				}, false), createHandle(state, ['base'], function(bounds)
6012				{
6013					var size = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'size', CalloutShape.prototype.size)));
6014					var position = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'position', CalloutShape.prototype.position)));
6015					var base = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'base', CalloutShape.prototype.base)));
6016
6017					return new mxPoint(bounds.x + Math.min(bounds.width, position * bounds.width + base), bounds.y + bounds.height - size);
6018				}, function(bounds, pt)
6019				{
6020					var position = Math.max(0, Math.min(1, mxUtils.getValue(this.state.style, 'position', CalloutShape.prototype.position)));
6021
6022					this.state.style['base'] = Math.round(Math.max(0, Math.min(bounds.width, pt.x - bounds.x - position * bounds.width)));
6023				}, false)];
6024
6025				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
6026				{
6027					handles.push(createArcHandle(state));
6028				}
6029
6030				return handles;
6031			},
6032			'internalStorage': function(state)
6033			{
6034				var handles = [createHandle(state, ['dx', 'dy'], function(bounds)
6035				{
6036					var dx = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'dx', InternalStorageShape.prototype.dx)));
6037					var dy = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'dy', InternalStorageShape.prototype.dy)));
6038
6039					return new mxPoint(bounds.x + dx, bounds.y + dy);
6040				}, function(bounds, pt)
6041				{
6042					this.state.style['dx'] = Math.round(Math.max(0, Math.min(bounds.width, pt.x - bounds.x)));
6043					this.state.style['dy'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)));
6044				}, false)];
6045
6046				if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false))
6047				{
6048					handles.push(createArcHandle(state));
6049				}
6050
6051				return handles;
6052			},
6053			'module': function(state)
6054			{
6055				var handles = [createHandle(state, ['jettyWidth', 'jettyHeight'], function(bounds)
6056				{
6057					var dx = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'jettyWidth', ModuleShape.prototype.jettyWidth)));
6058					var dy = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'jettyHeight', ModuleShape.prototype.jettyHeight)));
6059
6060					return new mxPoint(bounds.x + dx / 2, bounds.y + dy * 2);
6061				}, function(bounds, pt)
6062				{
6063					this.state.style['jettyWidth'] = Math.round(Math.max(0, Math.min(bounds.width, pt.x - bounds.x)) * 2);
6064					this.state.style['jettyHeight'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)) / 2);
6065				})];
6066
6067				return handles;
6068			},
6069			'corner': function(state)
6070			{
6071				return [createHandle(state, ['dx', 'dy'], function(bounds)
6072				{
6073					var dx = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'dx', CornerShape.prototype.dx)));
6074					var dy = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'dy', CornerShape.prototype.dy)));
6075
6076					return new mxPoint(bounds.x + dx, bounds.y + dy);
6077				}, function(bounds, pt)
6078				{
6079					this.state.style['dx'] = Math.round(Math.max(0, Math.min(bounds.width, pt.x - bounds.x)));
6080					this.state.style['dy'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)));
6081				}, false)];
6082			},
6083			'tee': function(state)
6084			{
6085				return [createHandle(state, ['dx', 'dy'], function(bounds)
6086				{
6087					var dx = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'dx', TeeShape.prototype.dx)));
6088					var dy = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'dy', TeeShape.prototype.dy)));
6089
6090					return new mxPoint(bounds.x + (bounds.width + dx) / 2, bounds.y + dy);
6091				}, function(bounds, pt)
6092				{
6093					this.state.style['dx'] = Math.round(Math.max(0, Math.min(bounds.width / 2, (pt.x - bounds.x - bounds.width / 2)) * 2));
6094					this.state.style['dy'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)));
6095				}, false)];
6096			},
6097			'singleArrow': createArrowHandleFunction(1),
6098			'doubleArrow': createArrowHandleFunction(0.5),
6099			'folder': function(state)
6100			{
6101				return [createHandle(state, ['tabWidth', 'tabHeight'], function(bounds)
6102				{
6103					var tw = Math.max(0, Math.min(bounds.width, mxUtils.getValue(this.state.style, 'tabWidth', FolderShape.prototype.tabWidth)));
6104					var th = Math.max(0, Math.min(bounds.height, mxUtils.getValue(this.state.style, 'tabHeight', FolderShape.prototype.tabHeight)));
6105
6106					if (mxUtils.getValue(this.state.style, 'tabPosition', FolderShape.prototype.tabPosition) == mxConstants.ALIGN_RIGHT)
6107					{
6108						tw = bounds.width - tw;
6109					}
6110
6111					return new mxPoint(bounds.x + tw, bounds.y + th);
6112				}, function(bounds, pt)
6113				{
6114					var tw = Math.max(0, Math.min(bounds.width, pt.x - bounds.x));
6115
6116					if (mxUtils.getValue(this.state.style, 'tabPosition', FolderShape.prototype.tabPosition) == mxConstants.ALIGN_RIGHT)
6117					{
6118						tw = bounds.width - tw;
6119					}
6120
6121					this.state.style['tabWidth'] = Math.round(tw);
6122					this.state.style['tabHeight'] = Math.round(Math.max(0, Math.min(bounds.height, pt.y - bounds.y)));
6123				}, false)];
6124			},
6125			'document': function(state)
6126			{
6127				return [createHandle(state, ['size'], function(bounds)
6128				{
6129					var size = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'size', DocumentShape.prototype.size))));
6130
6131					return new mxPoint(bounds.x + 3 * bounds.width / 4, bounds.y + (1 - size) * bounds.height);
6132				}, function(bounds, pt)
6133				{
6134					this.state.style['size'] = Math.max(0, Math.min(1, (bounds.y + bounds.height - pt.y) / bounds.height));
6135				}, false)];
6136			},
6137			'tape': function(state)
6138			{
6139				return [createHandle(state, ['size'], function(bounds)
6140				{
6141					var size = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'size', TapeShape.prototype.size))));
6142
6143					return new mxPoint(bounds.getCenterX(), bounds.y + size * bounds.height / 2);
6144				}, function(bounds, pt)
6145				{
6146					this.state.style['size'] = Math.max(0, Math.min(1, ((pt.y - bounds.y) / bounds.height) * 2));
6147				}, false)];
6148			},
6149			'isoCube2' : function(state)
6150			{
6151				return [createHandle(state, ['isoAngle'], function(bounds)
6152				{
6153					var isoAngle = Math.max(0.01, Math.min(94, parseFloat(mxUtils.getValue(this.state.style, 'isoAngle', IsoCubeShape2.isoAngle)))) * Math.PI / 200 ;
6154					var isoH = Math.min(bounds.width * Math.tan(isoAngle), bounds.height * 0.5);
6155
6156					return new mxPoint(bounds.x, bounds.y + isoH);
6157				}, function(bounds, pt)
6158				{
6159					this.state.style['isoAngle'] = Math.max(0, (pt.y - bounds.y) * 50 / bounds.height);
6160				}, true)];
6161			},
6162			'cylinder2' : createCylinderHandleFunction(CylinderShape.prototype.size),
6163			'cylinder3' : createCylinderHandleFunction(CylinderShape3.prototype.size),
6164			'offPageConnector': function(state)
6165			{
6166				return [createHandle(state, ['size'], function(bounds)
6167				{
6168					var size = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'size', OffPageConnectorShape.prototype.size))));
6169
6170					return new mxPoint(bounds.getCenterX(), bounds.y + (1 - size) * bounds.height);
6171				}, function(bounds, pt)
6172				{
6173					this.state.style['size'] = Math.max(0, Math.min(1, (bounds.y + bounds.height - pt.y) / bounds.height));
6174				}, false)];
6175			},
6176			'mxgraph.basic.rect': function(state)
6177			{
6178				var handles = [Graph.createHandle(state, ['size'], function(bounds)
6179				{
6180					var size = Math.max(0, Math.min(bounds.width / 2, bounds.height / 2, parseFloat(mxUtils.getValue(this.state.style, 'size', this.size))));
6181
6182					return new mxPoint(bounds.x + size, bounds.y + size);
6183				}, function(bounds, pt)
6184				{
6185					this.state.style['size'] = Math.round(100 * Math.max(0, Math.min(bounds.height / 2, bounds.width / 2, pt.x - bounds.x))) / 100;
6186				})];
6187
6188				var handle2 = Graph.createHandle(state, ['indent'], function(bounds)
6189				{
6190					var dx2 = Math.max(0, Math.min(100, parseFloat(mxUtils.getValue(this.state.style, 'indent', this.dx2))));
6191
6192					return new mxPoint(bounds.x + bounds.width * 0.75, bounds.y + dx2 * bounds.height / 200);
6193				}, function(bounds, pt)
6194				{
6195					this.state.style['indent'] = Math.round(100 * Math.max(0, Math.min(100, 200 * (pt.y - bounds.y) / bounds.height))) / 100;
6196				});
6197
6198				handles.push(handle2);
6199
6200				return handles;
6201			},
6202			'step': createDisplayHandleFunction(StepShape.prototype.size, true, null, true, StepShape.prototype.fixedSize),
6203			'hexagon': createDisplayHandleFunction(HexagonShape.prototype.size, true, 0.5, true, HexagonShape.prototype.fixedSize),
6204			'curlyBracket': createDisplayHandleFunction(CurlyBracketShape.prototype.size, false),
6205			'display': createDisplayHandleFunction(DisplayShape.prototype.size, false),
6206			'cube': createCubeHandleFunction(1, CubeShape.prototype.size, false),
6207			'card': createCubeHandleFunction(0.5, CardShape.prototype.size, true),
6208			'loopLimit': createCubeHandleFunction(0.5, LoopLimitShape.prototype.size, true),
6209			'trapezoid': createTrapezoidHandleFunction(0.5, TrapezoidShape.prototype.size, TrapezoidShape.prototype.fixedSize),
6210			'parallelogram': createTrapezoidHandleFunction(1, ParallelogramShape.prototype.size, ParallelogramShape.prototype.fixedSize)
6211		};
6212
6213		// Exposes custom handles
6214		Graph.createHandle = createHandle;
6215		Graph.handleFactory = handleFactory;
6216
6217		var vertexHandlerCreateCustomHandles = mxVertexHandler.prototype.createCustomHandles;
6218
6219		mxVertexHandler.prototype.createCustomHandles = function()
6220		{
6221			var handles = vertexHandlerCreateCustomHandles.apply(this, arguments);
6222
6223			if (this.graph.isCellRotatable(this.state.cell))
6224			// LATER: Make locked state independent of rotatable flag, fix toggle if default is false
6225			//if (this.graph.isCellResizable(this.state.cell) || this.graph.isCellMovable(this.state.cell))
6226			{
6227				var name = this.state.style['shape'];
6228
6229				if (mxCellRenderer.defaultShapes[name] == null &&
6230					mxStencilRegistry.getStencil(name) == null)
6231				{
6232					name = mxConstants.SHAPE_RECTANGLE;
6233				}
6234				else if (this.state.view.graph.isSwimlane(this.state.cell))
6235				{
6236					name = mxConstants.SHAPE_SWIMLANE;
6237				}
6238
6239				var fn = handleFactory[name];
6240
6241				if (fn == null && this.state.shape != null && this.state.shape.isRoundable())
6242				{
6243					fn = handleFactory[mxConstants.SHAPE_RECTANGLE];
6244				}
6245
6246				if (fn != null)
6247				{
6248					var temp = fn(this.state);
6249
6250					if (temp != null)
6251					{
6252						if (handles == null)
6253						{
6254							handles = temp;
6255						}
6256						else
6257						{
6258							handles = handles.concat(temp);
6259						}
6260					}
6261				}
6262			}
6263
6264			return handles;
6265		};
6266
6267		mxEdgeHandler.prototype.createCustomHandles = function()
6268		{
6269			var name = this.state.style['shape'];
6270
6271			if (mxCellRenderer.defaultShapes[name] == null &&
6272				mxStencilRegistry.getStencil(name) == null)
6273			{
6274				name = mxConstants.SHAPE_CONNECTOR;
6275			}
6276
6277			var fn = handleFactory[name];
6278
6279			if (fn != null)
6280			{
6281				return fn(this.state);
6282			}
6283
6284			return null;
6285		}
6286	}
6287	else
6288	{
6289		// Dummy entries to avoid NPE in embed mode
6290		Graph.createHandle = function() {};
6291		Graph.handleFactory = {};
6292	}
6293
6294	 var isoHVector = new mxPoint(1, 0);
6295	 var isoVVector = new mxPoint(1, 0);
6296
6297	 var alpha1 = mxUtils.toRadians(-30);
6298
6299	 var cos1 = Math.cos(alpha1);
6300	 var sin1 = Math.sin(alpha1);
6301
6302	 isoHVector = mxUtils.getRotatedPoint(isoHVector, cos1, sin1);
6303
6304	 var alpha2 = mxUtils.toRadians(-150);
6305
6306	 var cos2 = Math.cos(alpha2);
6307	 var sin2 = Math.sin(alpha2);
6308
6309	 isoVVector = mxUtils.getRotatedPoint(isoVVector, cos2, sin2);
6310
6311	 mxEdgeStyle.IsometricConnector = function (state, source, target, points, result)
6312	 {
6313		var view = state.view;
6314		var pt = (points != null && points.length > 0) ? points[0] : null;
6315		var pts = state.absolutePoints;
6316		var p0 = pts[0];
6317		var pe = pts[pts.length-1];
6318
6319		if (pt != null)
6320		{
6321			pt = view.transformControlPoint(state, pt);
6322		}
6323
6324		if (p0 == null)
6325		{
6326			if (source != null)
6327			{
6328				p0 = new mxPoint(source.getCenterX(), source.getCenterY());
6329			}
6330		}
6331
6332		if (pe == null)
6333		{
6334			if (target != null)
6335			{
6336				pe = new mxPoint(target.getCenterX(), target.getCenterY());
6337			}
6338		}
6339
6340		var a1 = isoHVector.x;
6341		var a2 = isoHVector.y;
6342
6343		var b1 = isoVVector.x;
6344		var b2 = isoVVector.y;
6345
6346		var elbow = mxUtils.getValue(state.style, 'elbow', 'horizontal') == 'horizontal';
6347
6348		if (pe != null && p0 != null)
6349		{
6350			var last = p0;
6351
6352			function isoLineTo(x, y, ignoreFirst)
6353			{
6354				var c1 = x - last.x;
6355				var c2 = y - last.y;
6356
6357				// Solves for isometric base vectors
6358				var h = (b2 * c1 - b1 * c2) / (a1 * b2 - a2 * b1);
6359				var v = (a2 * c1 - a1 * c2) / (a2 * b1 - a1 * b2);
6360
6361				if (elbow)
6362				{
6363					if (ignoreFirst)
6364					{
6365						last = new mxPoint(last.x + a1 * h, last.y + a2 * h);
6366						result.push(last);
6367					}
6368
6369					last = new mxPoint(last.x + b1 * v, last.y + b2 * v);
6370					result.push(last);
6371				}
6372				else
6373				{
6374					if (ignoreFirst)
6375					{
6376						last = new mxPoint(last.x + b1 * v, last.y + b2 * v);
6377						result.push(last);
6378					}
6379
6380					last = new mxPoint(last.x + a1 * h, last.y + a2 * h);
6381					result.push(last);
6382				}
6383			};
6384
6385			if (pt == null)
6386			{
6387				pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
6388			}
6389
6390			isoLineTo(pt.x, pt.y, true);
6391			isoLineTo(pe.x, pe.y, false);
6392		}
6393	 };
6394
6395	 mxStyleRegistry.putValue('isometricEdgeStyle', mxEdgeStyle.IsometricConnector);
6396
6397	 var graphCreateEdgeHandler = Graph.prototype.createEdgeHandler;
6398	 Graph.prototype.createEdgeHandler = function(state, edgeStyle)
6399	 {
6400	 	if (edgeStyle == mxEdgeStyle.IsometricConnector)
6401	 	{
6402	 		var handler = new mxElbowEdgeHandler(state);
6403	 		handler.snapToTerminals = false;
6404
6405	 		return handler;
6406	 	}
6407
6408	 	return graphCreateEdgeHandler.apply(this, arguments);
6409	 };
6410
6411	// Defines connection points for all shapes
6412	IsoRectangleShape.prototype.constraints = [];
6413
6414	IsoCubeShape.prototype.getConstraints = function(style, w, h)
6415	{
6416		var constr = [];
6417		var tan30 = Math.tan(mxUtils.toRadians(30));
6418		var tan30Dx = (0.5 - tan30) / 2;
6419		var m = Math.min(w, h / (0.5 + tan30));
6420		var dx = (w - m) / 2;
6421		var dy = (h - m) / 2;
6422
6423		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, dy + 0.25 * m));
6424		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx + 0.5 * m, dy + m * tan30Dx));
6425		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx + m, dy + 0.25 * m));
6426		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx + m, dy + 0.75 * m));
6427		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx + 0.5 * m, dy + (1 - tan30Dx) * m));
6428		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, dy + 0.75 * m));
6429
6430		return (constr);
6431	};
6432
6433	IsoCubeShape2.prototype.getConstraints = function(style, w, h)
6434	{
6435		var constr = [];
6436		var isoAngle = Math.max(0.01, Math.min(94, parseFloat(mxUtils.getValue(this.style, 'isoAngle', this.isoAngle)))) * Math.PI / 200 ;
6437		var isoH = Math.min(w * Math.tan(isoAngle), h * 0.5);
6438
6439		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6440		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, isoH));
6441		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6442		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, h - isoH));
6443		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6444		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h - isoH));
6445		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6446		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, isoH));
6447
6448		return (constr);
6449	}
6450
6451	CalloutShape.prototype.getConstraints = function(style, w, h)
6452	{
6453		var constr = [];
6454		var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
6455		var s = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
6456		var dx = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'position', this.position))));
6457		var dx2 = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'position2', this.position2))));
6458		var base = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'base', this.base))));
6459
6460		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6461		constr.push(new mxConnectionConstraint(new mxPoint(0.25, 0), false));
6462		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6463		constr.push(new mxConnectionConstraint(new mxPoint(0.75, 0), false));
6464		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false));
6465		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h - s) * 0.5));
6466		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, h - s));
6467		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx2, h));
6468		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h - s));
6469		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h - s) * 0.5));
6470
6471		if (w >= s * 2)
6472		{
6473			constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6474		}
6475
6476		return (constr);
6477	};
6478
6479	mxRectangleShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0), true),
6480											  new mxConnectionConstraint(new mxPoint(0.25, 0), true),
6481	                                          new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6482	                                          new mxConnectionConstraint(new mxPoint(0.75, 0), true),
6483	                                          new mxConnectionConstraint(new mxPoint(1, 0), true),
6484	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.25), true),
6485	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6486	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6487	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6488	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6489	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.75), true),
6490	        	            		 new mxConnectionConstraint(new mxPoint(0, 1), true),
6491	        	            		 new mxConnectionConstraint(new mxPoint(0.25, 1), true),
6492	        	            		 new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6493	        	            		 new mxConnectionConstraint(new mxPoint(0.75, 1), true),
6494	        	            		 new mxConnectionConstraint(new mxPoint(1, 1), true)];
6495	mxEllipse.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0), true), new mxConnectionConstraint(new mxPoint(1, 0), true),
6496	                                   new mxConnectionConstraint(new mxPoint(0, 1), true), new mxConnectionConstraint(new mxPoint(1, 1), true),
6497	                                   new mxConnectionConstraint(new mxPoint(0.5, 0), true), new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6498	          	              		   new mxConnectionConstraint(new mxPoint(0, 0.5), true), new mxConnectionConstraint(new mxPoint(1, 0.5))];
6499	PartialRectangleShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6500	mxImageShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6501	mxSwimlane.prototype.constraints = mxRectangleShape.prototype.constraints;
6502	PlusShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6503	mxLabel.prototype.constraints = mxRectangleShape.prototype.constraints;
6504
6505	NoteShape.prototype.getConstraints = function(style, w, h)
6506	{
6507		var constr = [];
6508		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
6509
6510		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6511		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - s) * 0.5, 0));
6512		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - s, 0));
6513		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - s * 0.5, s * 0.5));
6514		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, s));
6515		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h + s) * 0.5 ));
6516		constr.push(new mxConnectionConstraint(new mxPoint(1, 1), false));
6517		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6518		constr.push(new mxConnectionConstraint(new mxPoint(0, 1), false));
6519		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6520
6521		if (w >= s * 2)
6522		{
6523			constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6524		}
6525
6526		return (constr);
6527	};
6528
6529	CardShape.prototype.getConstraints = function(style, w, h)
6530	{
6531		var constr = [];
6532		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
6533
6534		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false));
6535		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + s) * 0.5, 0));
6536		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s, 0));
6537		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s * 0.5, s * 0.5));
6538		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, s));
6539		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h + s) * 0.5 ));
6540		constr.push(new mxConnectionConstraint(new mxPoint(0, 1), false));
6541		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6542		constr.push(new mxConnectionConstraint(new mxPoint(1, 1), false));
6543		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6544
6545		if (w >= s * 2)
6546		{
6547			constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6548		}
6549
6550		return (constr);
6551	};
6552
6553	CubeShape.prototype.getConstraints = function(style, w, h)
6554	{
6555		var constr = [];
6556		var s = Math.max(0, Math.min(w, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size)))));
6557
6558		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6559		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - s) * 0.5, 0));
6560		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - s, 0));
6561		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - s * 0.5, s * 0.5));
6562		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, s));
6563		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h + s) * 0.5));
6564		constr.push(new mxConnectionConstraint(new mxPoint(1, 1), false));
6565		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + s) * 0.5, h));
6566		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s, h));
6567		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s * 0.5, h - s * 0.5));
6568		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h - s));
6569		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h - s) * 0.5));
6570
6571		return (constr);
6572	};
6573
6574	CylinderShape3.prototype.getConstraints = function(style, w, h)
6575	{
6576		var constr = [];
6577		var s = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
6578
6579		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6580		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6581		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6582		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6583
6584		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, s));
6585		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false, null, 0, s));
6586		constr.push(new mxConnectionConstraint(new mxPoint(1, 1), false, null, 0, -s));
6587		constr.push(new mxConnectionConstraint(new mxPoint(0, 1), false, null, 0, -s));
6588
6589		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, s + (h * 0.5 - s) * 0.5));
6590		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false, null, 0, s + (h * 0.5 - s) * 0.5));
6591		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false, null, 0, h - s - (h * 0.5 - s) * 0.5));
6592		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h - s - (h * 0.5 - s) * 0.5));
6593
6594		constr.push(new mxConnectionConstraint(new mxPoint(0.145, 0), false, null, 0, s * 0.29));
6595		constr.push(new mxConnectionConstraint(new mxPoint(0.855, 0), false, null, 0, s * 0.29));
6596		constr.push(new mxConnectionConstraint(new mxPoint(0.855, 1), false, null, 0, -s * 0.29));
6597		constr.push(new mxConnectionConstraint(new mxPoint(0.145, 1), false, null, 0, -s * 0.29));
6598
6599		return (constr);
6600	};
6601
6602	FolderShape.prototype.getConstraints = function(style, w, h)
6603	{
6604		var constr = [];
6605		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'tabWidth', this.tabWidth))));
6606		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'tabHeight', this.tabHeight))));
6607		var tp = mxUtils.getValue(this.style, 'tabPosition', this.tabPosition);
6608
6609		if (tp == 'left')
6610		{
6611			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6612			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx * 0.5, 0));
6613			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, 0));
6614			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, dy));
6615			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + dx) * 0.5, dy));
6616		}
6617		else
6618		{
6619			constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false));
6620			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - dx * 0.5, 0));
6621			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - dx, 0));
6622			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - dx, dy));
6623			constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - dx) * 0.5, dy));
6624		}
6625
6626		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, dy));
6627		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h - dy) * 0.25 + dy));
6628		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h - dy) * 0.5 + dy));
6629		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, (h - dy) * 0.75 + dy));
6630		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, h));
6631		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, dy));
6632		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h - dy) * 0.25 + dy));
6633		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h - dy) * 0.5 + dy));
6634		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, (h - dy) * 0.75 + dy));
6635		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h));
6636		constr.push(new mxConnectionConstraint(new mxPoint(0.25, 1), false));
6637		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6638		constr.push(new mxConnectionConstraint(new mxPoint(0.75, 1), false));
6639
6640		return (constr);
6641	}
6642
6643	InternalStorageShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6644	DataStorageShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6645	TapeDataShape.prototype.constraints = mxEllipse.prototype.constraints;
6646	OrEllipseShape.prototype.constraints = mxEllipse.prototype.constraints;
6647	SumEllipseShape.prototype.constraints = mxEllipse.prototype.constraints;
6648	LineEllipseShape.prototype.constraints = mxEllipse.prototype.constraints;
6649	ManualInputShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6650	DelayShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6651
6652	DisplayShape.prototype.getConstraints = function(style, w, h)
6653	{
6654		var constr = [];
6655		var dx = Math.min(w, h / 2);
6656		var s = Math.min(w - dx, Math.max(0, parseFloat(mxUtils.getValue(this.style, 'size', this.size))) * w);
6657
6658		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false, null));
6659		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s, 0));
6660		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (s + w - dx) * 0.5, 0));
6661		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - dx, 0));
6662		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false, null));
6663		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - dx, h));
6664		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (s + w - dx) * 0.5, h));
6665		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, s, h));
6666
6667		return (constr);
6668	};
6669
6670	ModuleShape.prototype.getConstraints = function(style, w, h)
6671	{
6672		var x0 = parseFloat(mxUtils.getValue(style, 'jettyWidth', ModuleShape.prototype.jettyWidth)) / 2;
6673		var dy = parseFloat(mxUtils.getValue(style, 'jettyHeight', ModuleShape.prototype.jettyHeight));
6674		var constr = [new mxConnectionConstraint(new mxPoint(0, 0), false, null, x0),
6675			new mxConnectionConstraint(new mxPoint(0.25, 0), true),
6676			new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6677			new mxConnectionConstraint(new mxPoint(0.75, 0), true),
6678			new mxConnectionConstraint(new mxPoint(1, 0), true),
6679			new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6680			new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6681			new mxConnectionConstraint(new mxPoint(1, 0.75), true),
6682			new mxConnectionConstraint(new mxPoint(0, 1), false, null, x0),
6683			new mxConnectionConstraint(new mxPoint(0.25, 1), true),
6684			new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6685			new mxConnectionConstraint(new mxPoint(0.75, 1), true),
6686			new mxConnectionConstraint(new mxPoint(1, 1), true),
6687			new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, Math.min(h - 0.5 * dy, 1.5 * dy)),
6688			new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, Math.min(h - 0.5 * dy, 3.5 * dy))];
6689
6690		if (h > 5 * dy)
6691		{
6692			constr.push(new mxConnectionConstraint(new mxPoint(0, 0.75), false, null, x0));
6693		}
6694
6695		if (h > 8 * dy)
6696		{
6697			constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false, null, x0));
6698		}
6699
6700		if (h > 15 * dy)
6701		{
6702			constr.push(new mxConnectionConstraint(new mxPoint(0, 0.25), false, null, x0));
6703		}
6704
6705		return constr;
6706	};
6707
6708	LoopLimitShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6709	OffPageConnectorShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6710	mxCylinder.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.15, 0.05), false),
6711                                        new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6712                                        new mxConnectionConstraint(new mxPoint(0.85, 0.05), false),
6713      	              		 new mxConnectionConstraint(new mxPoint(0, 0.3), true),
6714      	              		 new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6715      	              		 new mxConnectionConstraint(new mxPoint(0, 0.7), true),
6716      	            		 new mxConnectionConstraint(new mxPoint(1, 0.3), true),
6717      	            		 new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6718      	            		 new mxConnectionConstraint(new mxPoint(1, 0.7), true),
6719      	            		 new mxConnectionConstraint(new mxPoint(0.15, 0.95), false),
6720      	            		 new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6721      	            		 new mxConnectionConstraint(new mxPoint(0.85, 0.95), false)];
6722	UmlActorShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0.1), false),
6723	                                          new mxConnectionConstraint(new mxPoint(0.5, 0), false),
6724	                                          new mxConnectionConstraint(new mxPoint(0.75, 0.1), false),
6725	        	              		 new mxConnectionConstraint(new mxPoint(0, 1/3), false),
6726	        	              		 new mxConnectionConstraint(new mxPoint(0, 1), false),
6727	        	            		 new mxConnectionConstraint(new mxPoint(1, 1/3), false),
6728	        	            		 new mxConnectionConstraint(new mxPoint(1, 1), false),
6729	        	            		 new mxConnectionConstraint(new mxPoint(0.5, 0.5), false)];
6730	ComponentShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0), true),
6731	                                          new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6732	                                          new mxConnectionConstraint(new mxPoint(0.75, 0), true),
6733	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.3), true),
6734	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.7), true),
6735	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6736	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6737	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.75), true),
6738	        	            		 new mxConnectionConstraint(new mxPoint(0.25, 1), true),
6739	        	            		 new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6740	        	            		 new mxConnectionConstraint(new mxPoint(0.75, 1), true)];
6741	mxActor.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6742   	              		 new mxConnectionConstraint(new mxPoint(0.25, 0.2), false),
6743   	              		 new mxConnectionConstraint(new mxPoint(0.1, 0.5), false),
6744   	              		 new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6745   	            		 new mxConnectionConstraint(new mxPoint(0.75, 0.25), false),
6746   	            		 new mxConnectionConstraint(new mxPoint(0.9, 0.5), false),
6747   	            		 new mxConnectionConstraint(new mxPoint(1, 0.75), true),
6748   	            		 new mxConnectionConstraint(new mxPoint(0.25, 1), true),
6749   	            		 new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6750   	            		 new mxConnectionConstraint(new mxPoint(0.75, 1), true)];
6751	SwitchShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0), false),
6752                                         new mxConnectionConstraint(new mxPoint(0.5, 0.25), false),
6753                                         new mxConnectionConstraint(new mxPoint(1, 0), false),
6754			       	              		 new mxConnectionConstraint(new mxPoint(0.25, 0.5), false),
6755			       	              		 new mxConnectionConstraint(new mxPoint(0.75, 0.5), false),
6756			       	              		 new mxConnectionConstraint(new mxPoint(0, 1), false),
6757			       	            		 new mxConnectionConstraint(new mxPoint(0.5, 0.75), false),
6758			       	            		 new mxConnectionConstraint(new mxPoint(1, 1), false)];
6759	TapeShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.35), false),
6760	                                   new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6761	                                   new mxConnectionConstraint(new mxPoint(0, 0.65), false),
6762	                                   new mxConnectionConstraint(new mxPoint(1, 0.35), false),
6763		                                new mxConnectionConstraint(new mxPoint(1, 0.5), false),
6764		                                new mxConnectionConstraint(new mxPoint(1, 0.65), false),
6765										new mxConnectionConstraint(new mxPoint(0.25, 1), false),
6766										new mxConnectionConstraint(new mxPoint(0.75, 0), false)];
6767	StepShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0), true),
6768									new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6769									new mxConnectionConstraint(new mxPoint(0.75, 0), true),
6770									new mxConnectionConstraint(new mxPoint(0.25, 1), true),
6771									new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6772									new mxConnectionConstraint(new mxPoint(0.75, 1), true),
6773									new mxConnectionConstraint(new mxPoint(0, 0.25), true),
6774									new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6775									new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6776									new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6777									new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6778									new mxConnectionConstraint(new mxPoint(1, 0.75), true)];
6779	mxLine.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6780	                                new mxConnectionConstraint(new mxPoint(0.25, 0.5), false),
6781	                                new mxConnectionConstraint(new mxPoint(0.75, 0.5), false),
6782									new mxConnectionConstraint(new mxPoint(1, 0.5), false)];
6783	LollipopShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.5, 0), false),
6784										new mxConnectionConstraint(new mxPoint(0.5, 1), false)];
6785	mxDoubleEllipse.prototype.constraints = mxEllipse.prototype.constraints;
6786	mxRhombus.prototype.constraints = mxEllipse.prototype.constraints;
6787	mxTriangle.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.25), true),
6788	                                    new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6789	                                   new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6790	                                   new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6791	                                   new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6792	                                   new mxConnectionConstraint(new mxPoint(1, 0.5), true)];
6793	mxHexagon.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.375, 0), true),
6794	                                    new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6795	                                   new mxConnectionConstraint(new mxPoint(0.625, 0), true),
6796	                                   new mxConnectionConstraint(new mxPoint(0, 0.25), true),
6797	                                   new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6798	                                   new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6799	                                   new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6800	                                   new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6801	                                   new mxConnectionConstraint(new mxPoint(1, 0.75), true),
6802	                                   new mxConnectionConstraint(new mxPoint(0.375, 1), true),
6803	                                    new mxConnectionConstraint(new mxPoint(0.5, 1), true),
6804	                                   new mxConnectionConstraint(new mxPoint(0.625, 1), true)];
6805	mxCloud.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0.25), false),
6806	                                 new mxConnectionConstraint(new mxPoint(0.4, 0.1), false),
6807	                                 new mxConnectionConstraint(new mxPoint(0.16, 0.55), false),
6808	                                 new mxConnectionConstraint(new mxPoint(0.07, 0.4), false),
6809	                                 new mxConnectionConstraint(new mxPoint(0.31, 0.8), false),
6810	                                 new mxConnectionConstraint(new mxPoint(0.13, 0.77), false),
6811	                                 new mxConnectionConstraint(new mxPoint(0.8, 0.8), false),
6812	                                 new mxConnectionConstraint(new mxPoint(0.55, 0.95), false),
6813	                                 new mxConnectionConstraint(new mxPoint(0.875, 0.5), false),
6814	                                 new mxConnectionConstraint(new mxPoint(0.96, 0.7), false),
6815	                                 new mxConnectionConstraint(new mxPoint(0.625, 0.2), false),
6816	                                 new mxConnectionConstraint(new mxPoint(0.88, 0.25), false)];
6817	ParallelogramShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6818	TrapezoidShape.prototype.constraints = mxRectangleShape.prototype.constraints;
6819	DocumentShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0), true),
6820	                                          new mxConnectionConstraint(new mxPoint(0.5, 0), true),
6821	                                          new mxConnectionConstraint(new mxPoint(0.75, 0), true),
6822	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.25), true),
6823	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.5), true),
6824	        	              		 new mxConnectionConstraint(new mxPoint(0, 0.75), true),
6825	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.25), true),
6826	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.5), true),
6827	        	            		 new mxConnectionConstraint(new mxPoint(1, 0.75), true)];
6828	mxArrow.prototype.constraints = null;
6829
6830	TeeShape.prototype.getConstraints = function(style, w, h)
6831	{
6832		var constr = [];
6833		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
6834		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))));
6835		var w2 = Math.abs(w - dx) / 2;
6836
6837		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6838		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6839		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false));
6840		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, dy * 0.5));
6841		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, dy));
6842		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w * 0.75 + dx * 0.25, dy));
6843		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + dx) * 0.5, dy));
6844		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + dx) * 0.5, (h + dy) * 0.5));
6845		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + dx) * 0.5, h));
6846		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6847		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - dx) * 0.5, h));
6848		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - dx) * 0.5, (h + dy) * 0.5));
6849		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - dx) * 0.5, dy));
6850		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w * 0.25 - dx * 0.25, dy));
6851		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, dy));
6852		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, dy * 0.5));
6853
6854		return (constr);
6855	};
6856
6857	CornerShape.prototype.getConstraints = function(style, w, h)
6858	{
6859		var constr = [];
6860		var dx = Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
6861		var dy = Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))));
6862
6863		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false));
6864		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6865		constr.push(new mxConnectionConstraint(new mxPoint(1, 0), false));
6866		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, dy * 0.5));
6867		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, dy));
6868		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + dx) * 0.5, dy));
6869		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, dy));
6870		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, (h + dy) * 0.5));
6871		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx, h));
6872		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, dx * 0.5, h));
6873		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6874		constr.push(new mxConnectionConstraint(new mxPoint(0, 1), false));
6875
6876		return (constr);
6877	};
6878
6879	CrossbarShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0), false),
6880        new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6881        new mxConnectionConstraint(new mxPoint(0, 1), false),
6882        new mxConnectionConstraint(new mxPoint(0.25, 0.5), false),
6883        new mxConnectionConstraint(new mxPoint(0.5, 0.5), false),
6884        new mxConnectionConstraint(new mxPoint(0.75, 0.5), false),
6885        new mxConnectionConstraint(new mxPoint(1, 0), false),
6886        new mxConnectionConstraint(new mxPoint(1, 0.5), false),
6887        new mxConnectionConstraint(new mxPoint(1, 1), false)];
6888
6889	SingleArrowShape.prototype.getConstraints = function(style, w, h)
6890	{
6891		var constr = [];
6892		var aw = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowWidth', this.arrowWidth))));
6893		var as = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowSize', this.arrowSize))));
6894		var at = (h - aw) / 2;
6895		var ab = at + aw;
6896
6897		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6898		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, at));
6899		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - as) * 0.5, at));
6900		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - as, 0));
6901		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6902		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - as, h));
6903		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w - as) * 0.5, h - at));
6904		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, h - at));
6905
6906		return (constr);
6907	};
6908
6909	DoubleArrowShape.prototype.getConstraints = function(style, w, h)
6910	{
6911		var constr = [];
6912		var aw = h * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowWidth', SingleArrowShape.prototype.arrowWidth))));
6913		var as = w * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'arrowSize', SingleArrowShape.prototype.arrowSize))));
6914		var at = (h - aw) / 2;
6915		var ab = at + aw;
6916
6917		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6918		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, as, 0));
6919		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w * 0.5, at));
6920		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - as, 0));
6921		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6922		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w - as, h));
6923		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w * 0.5, h - at));
6924		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, as, h));
6925
6926		return (constr);
6927	};
6928
6929	CrossShape.prototype.getConstraints = function(style, w, h)
6930	{
6931		var constr = [];
6932		var m = Math.min(h, w);
6933		var size = Math.max(0, Math.min(m, m * parseFloat(mxUtils.getValue(this.style, 'size', this.size))));
6934		var t = (h - size) / 2;
6935		var b = t + size;
6936		var l = (w - size) / 2;
6937		var r = l + size;
6938
6939		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, t * 0.5));
6940		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, 0));
6941		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 0), false));
6942		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, 0));
6943		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, t * 0.5));
6944		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, t));
6945		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, h - t * 0.5));
6946		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, h));
6947		constr.push(new mxConnectionConstraint(new mxPoint(0.5, 1), false));
6948		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, h));
6949		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, h - t * 0.5));
6950		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, r, b));
6951		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + r) * 0.5, t));
6952		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, t));
6953		constr.push(new mxConnectionConstraint(new mxPoint(1, 0.5), false));
6954		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, w, b));
6955		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, (w + r) * 0.5, b));
6956		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, b));
6957		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l * 0.5, t));
6958		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, t));
6959		constr.push(new mxConnectionConstraint(new mxPoint(0, 0.5), false));
6960		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, 0, b));
6961		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l * 0.5, b));
6962		constr.push(new mxConnectionConstraint(new mxPoint(0, 0), false, null, l, t));
6963
6964		return (constr);
6965	};
6966
6967	UmlLifeline.prototype.constraints = null;
6968	OrShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.25), false),
6969	  	                             new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6970	  	                             new mxConnectionConstraint(new mxPoint(0, 0.75), false),
6971	  	                             new mxConnectionConstraint(new mxPoint(1, 0.5), false),
6972	  	                             new mxConnectionConstraint(new mxPoint(0.7, 0.1), false),
6973	  	                             new mxConnectionConstraint(new mxPoint(0.7, 0.9), false)];
6974	XorShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.175, 0.25), false),
6975	  	                             new mxConnectionConstraint(new mxPoint(0.25, 0.5), false),
6976	  	                             new mxConnectionConstraint(new mxPoint(0.175, 0.75), false),
6977	  	                             new mxConnectionConstraint(new mxPoint(1, 0.5), false),
6978	  	                             new mxConnectionConstraint(new mxPoint(0.7, 0.1), false),
6979	  	                             new mxConnectionConstraint(new mxPoint(0.7, 0.9), false)];
6980	RequiredInterfaceShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6981          new mxConnectionConstraint(new mxPoint(1, 0.5), false)];
6982	ProvidedRequiredInterfaceShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0, 0.5), false),
6983        new mxConnectionConstraint(new mxPoint(1, 0.5), false)];
6984})();
6985