text: /*
  	Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
  	Available via Academic Free License >= 2.1 OR the modified BSD license.
  	see: http://dojotoolkit.org/license for details
  */
  
  /*
  	This is an optimized version of Dojo, built for deployment and not for
  	development. To get sources and documentation, please visit:
  
  		http://dojotoolkit.org
  */
  
  if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojox.gfx.matrix"] = true;
  dojo.provide("dojox.gfx.matrix");
  
  (function(){
  	var m = dojox.gfx.matrix;
  
  	// candidates for dojox.math:
  	var _degToRadCache = {};
  	m._degToRad = function(degree){
  		return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180));
  	};
  	m._radToDeg = function(radian){ return radian / Math.PI * 180; };
  
  	m.Matrix2D = function(arg){
  		// summary: a 2D matrix object
  		// description: Normalizes a 2D matrix-like object. If arrays is passed,
  		//		all objects of the array are normalized and multiplied sequentially.
  		// arg: Object
  		//		a 2D matrix-like object, a number, or an array of such objects
  		if(arg){
  			if(typeof arg == "number"){
  				this.xx = this.yy = arg;
  			}else if(arg instanceof Array){
  				if(arg.length > 0){
  					var matrix = m.normalize(arg[0]);
  					// combine matrices
  					for(var i = 1; i < arg.length; ++i){
  						var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]);
  						matrix = new m.Matrix2D();
  						matrix.xx = l.xx * r.xx + l.xy * r.yx;
  						matrix.xy = l.xx * r.xy + l.xy * r.yy;
  						matrix.yx = l.yx * r.xx + l.yy * r.yx;
  						matrix.yy = l.yx * r.xy + l.yy * r.yy;
  						matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  						matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  					}
  					dojo.mixin(this, matrix);
  				}
  			}else{
  				dojo.mixin(this, arg);
  			}
  		}
  	};
  
  	// the default (identity) matrix, which is used to fill in missing values
  	dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
  
  	dojo.mixin(m, {
  		// summary: class constants, and methods of dojox.gfx.matrix
  
  		// matrix constants
  
  		// identity: dojox.gfx.matrix.Matrix2D
  		//		an identity matrix constant: identity * (x, y) == (x, y)
  		identity: new m.Matrix2D(),
  
  		// flipX: dojox.gfx.matrix.Matrix2D
  		//		a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
  		flipX:    new m.Matrix2D({xx: -1}),
  
  		// flipY: dojox.gfx.matrix.Matrix2D
  		//		a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
  		flipY:    new m.Matrix2D({yy: -1}),
  
  		// flipXY: dojox.gfx.matrix.Matrix2D
  		//		a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
  		flipXY:   new m.Matrix2D({xx: -1, yy: -1}),
  
  		// matrix creators
  
  		translate: function(a, b){
  			// summary: forms a translation matrix
  			// description: The resulting matrix is used to translate (move) points by specified offsets.
  			// a: Number: an x coordinate value
  			// b: Number: a y coordinate value
  			if(arguments.length > 1){
  				return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D
  			}
  			// branch
  			// a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions
  			// b: null
  			return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D
  		},
  		scale: function(a, b){
  			// summary: forms a scaling matrix
  			// description: The resulting matrix is used to scale (magnify) points by specified offsets.
  			// a: Number: a scaling factor used for the x coordinate
  			// b: Number: a scaling factor used for the y coordinate
  			if(arguments.length > 1){
  				return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D
  			}
  			if(typeof a == "number"){
  				// branch
  				// a: Number: a uniform scaling factor used for the both coordinates
  				// b: null
  				return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D
  			}
  			// branch
  			// a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions
  			// b: null
  			return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D
  		},
  		rotate: function(angle){
  			// summary: forms a rotating matrix
  			// description: The resulting matrix is used to rotate points
  			//		around the origin of coordinates (0, 0) by specified angle.
  			// angle: Number: an angle of rotation in radians (>0 for CW)
  			var c = Math.cos(angle);
  			var s = Math.sin(angle);
  			return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D
  		},
  		rotateg: function(degree){
  			// summary: forms a rotating matrix
  			// description: The resulting matrix is used to rotate points
  			//		around the origin of coordinates (0, 0) by specified degree.
  			//		See dojox.gfx.matrix.rotate() for comparison.
  			// degree: Number: an angle of rotation in degrees (>0 for CW)
  			return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  		},
  		skewX: function(angle) {
  			// summary: forms an x skewing matrix
  			// description: The resulting matrix is used to skew points in the x dimension
  			//		around the origin of coordinates (0, 0) by specified angle.
  			// angle: Number: an skewing angle in radians
  			return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  		},
  		skewXg: function(degree){
  			// summary: forms an x skewing matrix
  			// description: The resulting matrix is used to skew points in the x dimension
  			//		around the origin of coordinates (0, 0) by specified degree.
  			//		See dojox.gfx.matrix.skewX() for comparison.
  			// degree: Number: an skewing angle in degrees
  			return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  		},
  		skewY: function(angle){
  			// summary: forms a y skewing matrix
  			// description: The resulting matrix is used to skew points in the y dimension
  			//		around the origin of coordinates (0, 0) by specified angle.
  			// angle: Number: an skewing angle in radians
  			return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  		},
  		skewYg: function(degree){
  			// summary: forms a y skewing matrix
  			// description: The resulting matrix is used to skew points in the y dimension
  			//		around the origin of coordinates (0, 0) by specified degree.
  			//		See dojox.gfx.matrix.skewY() for comparison.
  			// degree: Number: an skewing angle in degrees
  			return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  		},
  		reflect: function(a, b){
  			// summary: forms a reflection matrix
  			// description: The resulting matrix is used to reflect points around a vector,
  			//		which goes through the origin.
  			// a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection
  			// b: null
  			if(arguments.length == 1){
  				b = a.y;
  				a = a.x;
  			}
  			// branch
  			// a: Number: an x coordinate value
  			// b: Number: a y coordinate value
  
  			// make a unit vector
  			var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2;
  			return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D
  		},
  		project: function(a, b){
  			// summary: forms an orthogonal projection matrix
  			// description: The resulting matrix is used to project points orthogonally on a vector,
  			//		which goes through the origin.
  			// a: dojox.gfx.Point: a point-like object, which specifies a vector of projection
  			// b: null
  			if(arguments.length == 1){
  				b = a.y;
  				a = a.x;
  			}
  			// branch
  			// a: Number: an x coordinate value
  			// b: Number: a y coordinate value
  
  			// make a unit vector
  			var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
  			return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D
  		},
  
  		// ensure matrix 2D conformance
  		normalize: function(matrix){
  			// summary: converts an object to a matrix, if necessary
  			// description: Converts any 2D matrix-like object or an array of
  			//		such objects to a valid dojox.gfx.matrix.Matrix2D object.
  			// matrix: Object: an object, which is converted to a matrix, if necessary
  			return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D
  		},
  
  		// common operations
  
  		clone: function(matrix){
  			// summary: creates a copy of a 2D matrix
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned
  			var obj = new m.Matrix2D();
  			for(var i in matrix){
  				if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
  			}
  			return obj; // dojox.gfx.matrix.Matrix2D
  		},
  		invert: function(matrix){
  			// summary: inverts a 2D matrix
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted
  			var M = m.normalize(matrix),
  				D = M.xx * M.yy - M.xy * M.yx,
  				M = new m.Matrix2D({
  					xx: M.yy/D, xy: -M.xy/D,
  					yx: -M.yx/D, yy: M.xx/D,
  					dx: (M.xy * M.dy - M.yy * M.dx) / D,
  					dy: (M.yx * M.dx - M.xx * M.dy) / D
  				});
  			return M; // dojox.gfx.matrix.Matrix2D
  		},
  		_multiplyPoint: function(matrix, x, y){
  			// summary: applies a matrix to a point
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  			// x: Number: an x coordinate of a point
  			// y: Number: a y coordinate of a point
  			return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point
  		},
  		multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){
  			// summary: applies a matrix to a point
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  			// a: Number: an x coordinate of a point
  			// b: Number: a y coordinate of a point
  			var M = m.normalize(matrix);
  			if(typeof a == "number" && typeof b == "number"){
  				return m._multiplyPoint(M, a, b); // dojox.gfx.Point
  			}
  			// branch
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  			// a: dojox.gfx.Point: a point
  			// b: null
  			return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point
  		},
  		multiply: function(matrix){
  			// summary: combines matrices by multiplying them sequentially in the given order
  			// matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object,
  			//		all subsequent arguments are matrix-like objects too
  			var M = m.normalize(matrix);
  			// combine matrices
  			for(var i = 1; i < arguments.length; ++i){
  				var l = M, r = m.normalize(arguments[i]);
  				M = new m.Matrix2D();
  				M.xx = l.xx * r.xx + l.xy * r.yx;
  				M.xy = l.xx * r.xy + l.xy * r.yy;
  				M.yx = l.yx * r.xx + l.yy * r.yx;
  				M.yy = l.yx * r.xy + l.yy * r.yy;
  				M.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  				M.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  			}
  			return M; // dojox.gfx.matrix.Matrix2D
  		},
  
  		// high level operations
  
  		_sandwich: function(matrix, x, y){
  			// summary: applies a matrix at a centrtal point
  			// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point
  			// x: Number: an x component of the central point
  			// y: Number: a y component of the central point
  			return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D
  		},
  		scaleAt: function(a, b, c, d){
  			// summary: scales a picture using a specified point as a center of scaling
  			// description: Compare with dojox.gfx.matrix.scale().
  			// a: Number: a scaling factor used for the x coordinate
  			// b: Number: a scaling factor used for the y coordinate
  			// c: Number: an x component of a central point
  			// d: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) uniform scale factor, Point
  			//	2) uniform scale factor, x, y
  			//	3) x scale, y scale, Point
  			//	4) x scale, y scale, x, y
  
  			switch(arguments.length){
  				case 4:
  					// a and b are scale factor components, c and d are components of a point
  					return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D
  				case 3:
  					if(typeof c == "number"){
  						// branch
  						// a: Number: a uniform scaling factor used for both coordinates
  						// b: Number: an x component of a central point
  						// c: Number: a y component of a central point
  						// d: null
  						return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D
  					}
  					// branch
  					// a: Number: a scaling factor used for the x coordinate
  					// b: Number: a scaling factor used for the y coordinate
  					// c: dojox.gfx.Point: a central point
  					// d: null
  					return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D
  			}
  			// branch
  			// a: Number: a uniform scaling factor used for both coordinates
  			// b: dojox.gfx.Point: a central point
  			// c: null
  			// d: null
  			return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D
  		},
  		rotateAt: function(angle, a, b){
  			// summary: rotates a picture using a specified point as a center of rotation
  			// description: Compare with dojox.gfx.matrix.rotate().
  			// angle: Number: an angle of rotation in radians (>0 for CW)
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) rotation angle in radians, Point
  			//	2) rotation angle in radians, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// angle: Number: an angle of rotation in radians (>0 for CCW)
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		},
  		rotategAt: function(degree, a, b){
  			// summary: rotates a picture using a specified point as a center of rotation
  			// description: Compare with dojox.gfx.matrix.rotateg().
  			// degree: Number: an angle of rotation in degrees (>0 for CW)
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) rotation angle in degrees, Point
  			//	2) rotation angle in degrees, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// degree: Number: an angle of rotation in degrees (>0 for CCW)
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		},
  		skewXAt: function(angle, a, b){
  			// summary: skews a picture along the x axis using a specified point as a center of skewing
  			// description: Compare with dojox.gfx.matrix.skewX().
  			// angle: Number: an skewing angle in radians
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) skew angle in radians, Point
  			//	2) skew angle in radians, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// angle: Number: an skewing angle in radians
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		},
  		skewXgAt: function(degree, a, b){
  			// summary: skews a picture along the x axis using a specified point as a center of skewing
  			// description: Compare with dojox.gfx.matrix.skewXg().
  			// degree: Number: an skewing angle in degrees
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) skew angle in degrees, Point
  			//	2) skew angle in degrees, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// degree: Number: an skewing angle in degrees
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		},
  		skewYAt: function(angle, a, b){
  			// summary: skews a picture along the y axis using a specified point as a center of skewing
  			// description: Compare with dojox.gfx.matrix.skewY().
  			// angle: Number: an skewing angle in radians
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) skew angle in radians, Point
  			//	2) skew angle in radians, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// angle: Number: an skewing angle in radians
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		},
  		skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
  			// summary: skews a picture along the y axis using a specified point as a center of skewing
  			// description: Compare with dojox.gfx.matrix.skewYg().
  			// degree: Number: an skewing angle in degrees
  			// a: Number: an x component of a central point
  			// b: Number: a y component of a central point
  
  			// accepts several signatures:
  			//	1) skew angle in degrees, Point
  			//	2) skew angle in degrees, x, y
  
  			if(arguments.length > 2){
  				return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  			}
  
  			// branch
  			// degree: Number: an skewing angle in degrees
  			// a: dojox.gfx.Point: a central point
  			// b: null
  			return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  		}
  
  		//TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
  
  	});
  })();
  
  // propagate Matrix2D up
  dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D;
  
  }
  
  if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojox.gfx._base"] = true;
  dojo.provide("dojox.gfx._base");
  
  (function(){
  	var g = dojox.gfx, b = g._base;
  
  	// candidates for dojox.style (work on VML and SVG nodes)
  	g._hasClass = function(/*DomNode*/node, /*String*/classStr){
  		//	summary:
  		//		Returns whether or not the specified classes are a portion of the
  		//		class list currently applied to the node.
  		// return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className)	// Boolean
  		var cls = node.getAttribute("className");
  		return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0;  // Boolean
  	}
  	g._addClass = function(/*DomNode*/node, /*String*/classStr){
  		//	summary:
  		//		Adds the specified classes to the end of the class list on the
  		//		passed node.
  		var cls = node.getAttribute("className") || "";
  		if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){
  			node.setAttribute("className", cls + (cls ? " " : "") + classStr);
  		}
  	}
  	g._removeClass = function(/*DomNode*/node, /*String*/classStr){
  		//	summary: Removes classes from node.
  		var cls = node.getAttribute("className");
  		if(cls){
  			node.setAttribute(
  				"className", 
  				cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2")
  			);
  		}
  	}
  
  	// candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
  
  	//	derived from Morris John's emResized measurer
  	b._getFontMeasurements = function(){
  		//	summary:
  		//		Returns an object that has pixel equivilents of standard font
  		//		size values.
  		var heights = {
  			'1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0,
  			'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0,
  			'xx-large': 0
  		};
  
  		if(dojo.isIE){
  			//	we do a font-size fix if and only if one isn't applied already.
  			//	NOTE: If someone set the fontSize on the HTML Element, this will kill it.
  			dojo.doc.documentElement.style.fontSize="100%";
  		}
  
  		//	set up the measuring node.
  		var div = dojo.doc.createElement("div");
  		var s = div.style;
  		s.position = "absolute";
  		s.left = "-100px";
  		s.top = "0px";
  		s.width = "30px";
  		s.height = "1000em";
  		s.borderWidth = "0px";
  		s.margin = "0px";
  		s.padding = "0px";
  		s.outline = "none";
  		s.lineHeight = "1";
  		s.overflow = "hidden";
  		dojo.body().appendChild(div);
  
  		//	do the measurements.
  		for(var p in heights){
  			div.style.fontSize = p;
  			heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
  		}
  
  		dojo.body().removeChild(div);
  		div = null;
  		return heights; 	//	object
  	};
  
  	var fontMeasurements = null;
  
  	b._getCachedFontMeasurements = function(recalculate){
  		if(recalculate || !fontMeasurements){
  			fontMeasurements = b._getFontMeasurements();
  		}
  		return fontMeasurements;
  	};
  
  	// candidate for dojox.html.metrics
  
  	var measuringNode = null, empty = {};
  	b._getTextBox = function(	/*String*/ text,
  								/*Object*/ style,
  								/*String?*/ className){
  		var m, s, al = arguments.length;
  		if(!measuringNode){
  			m = measuringNode = dojo.doc.createElement("div");
  			s = m.style;
  			s.position = "absolute";
  			s.left = "-10000px";
  			s.top = "0";
  			dojo.body().appendChild(m);
  		}else{
  			m = measuringNode;
  			s = m.style;
  		}
  		// reset styles
  		m.className = "";
  		s.borderWidth = "0";
  		s.margin = "0";
  		s.padding = "0";
  		s.outline = "0";
  		// set new style
  		if(al > 1 && style){
  			for(var i in style){
  				if(i in empty){ continue; }
  				s[i] = style[i];
  			}
  		}
  		// set classes
  		if(al > 2 && className){
  			m.className = className;
  		}
  		// take a measure
  		m.innerHTML = text;
  
  		if(m["getBoundingClientRect"]){
  			var bcr = m.getBoundingClientRect();
  			return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
  		}else{
  			return dojo.marginBox(m);
  		}
  	};
  
  	// candidate for dojo.dom
  
  	var uniqueId = 0;
  	b._getUniqueId = function(){
  		// summary: returns a unique string for use with any DOM element
  		var id;
  		do{
  			id = dojo._scopeName + "Unique" + (++uniqueId);
  		}while(dojo.byId(id));
  		return id;
  	};
  })();
  
  dojo.mixin(dojox.gfx, {
  	//	summary:
  	// 		defines constants, prototypes, and utility functions
  
  	// default shapes, which are used to fill in missing parameters
  	defaultPath: {
  		type: "path", path: ""
  	},
  	defaultPolyline: {
  		type: "polyline", points: []
  	},
  	defaultRect: {
  		type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0
  	},
  	defaultEllipse: {
  		type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100
  	},
  	defaultCircle: {
  		type: "circle", cx: 0, cy: 0, r: 100
  	},
  	defaultLine: {
  		type: "line", x1: 0, y1: 0, x2: 100, y2: 100
  	},
  	defaultImage: {
  		type: "image", x: 0, y: 0, width: 0, height: 0, src: ""
  	},
  	defaultText: {
  		type: "text", x: 0, y: 0, text: "", align: "start",
  		decoration: "none", rotated: false, kerning: true
  	},
  	defaultTextPath: {
  		type: "textpath", text: "", align: "start",
  		decoration: "none", rotated: false, kerning: true
  	},
  
  	// default geometric attributes
  	defaultStroke: {
  		type: "stroke", color: "black", style: "solid", width: 1, 
  		cap: "butt", join: 4
  	},
  	defaultLinearGradient: {
  		type: "linear", x1: 0, y1: 0, x2: 100, y2: 100,
  		colors: [
  			{ offset: 0, color: "black" }, { offset: 1, color: "white" }
  		]
  	},
  	defaultRadialGradient: {
  		type: "radial", cx: 0, cy: 0, r: 100,
  		colors: [
  			{ offset: 0, color: "black" }, { offset: 1, color: "white" }
  		]
  	},
  	defaultPattern: {
  		type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""
  	},
  	defaultFont: {
  		type: "font", style: "normal", variant: "normal", 
  		weight: "normal", size: "10pt", family: "serif"
  	},
  
  	getDefault: (function(){
  		var typeCtorCache = {};
  		// a memoized delegate()
  		return function(/*String*/ type){
  			var t = typeCtorCache[type];
  			if(t){
  				return new t();
  			}
  			t = typeCtorCache[type] = new Function;
  			t.prototype = dojox.gfx[ "default" + type ];
  			return new t();
  		}
  	})(),
  
  	normalizeColor: function(/*Color*/ color){
  		//	summary:
  		// 		converts any legal color representation to normalized
  		// 		dojo.Color object
  		return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color
  	},
  	normalizeParameters: function(existed, update){
  		//	summary:
  		// 		updates an existing object with properties from an "update"
  		// 		object
  		//	existed: Object
  		//		the "target" object to be updated
  		//	update:  Object
  		//		the "update" object, whose properties will be used to update
  		//		the existed object
  		if(update){
  			var empty = {};
  			for(var x in existed){
  				if(x in update && !(x in empty)){
  					existed[x] = update[x];
  				}
  			}
  		}
  		return existed;	// Object
  	},
  	makeParameters: function(defaults, update){
  		//	summary:
  		// 		copies the original object, and all copied properties from the
  		// 		"update" object
  		//	defaults: Object
  		//		the object to be cloned before updating
  		//	update:   Object
  		//		the object, which properties are to be cloned during updating
  		if(!update){
  			// return dojo.clone(defaults);
  			return dojo.delegate(defaults);
  		}
  		var result = {};
  		for(var i in defaults){
  			if(!(i in result)){
  				result[i] = dojo.clone((i in update) ? update[i] : defaults[i]);
  			}
  		}
  		return result; // Object
  	},
  	formatNumber: function(x, addSpace){
  		// summary: converts a number to a string using a fixed notation
  		// x:			Number:		number to be converted
  		// addSpace:	Boolean?:	if it is true, add a space before a positive number
  		var val = x.toString();
  		if(val.indexOf("e") >= 0){
  			val = x.toFixed(4);
  		}else{
  			var point = val.indexOf(".");
  			if(point >= 0 && val.length - point > 5){
  				val = x.toFixed(4);
  			}
  		}
  		if(x < 0){
  			return val; // String
  		}
  		return addSpace ? " " + val : val; // String
  	},
  	// font operations
  	makeFontString: function(font){
  		// summary: converts a font object to a CSS font string
  		// font:	Object:	font object (see dojox.gfx.defaultFont)
  		return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
  	},
  	splitFontString: function(str){
  		// summary:
  		//		converts a CSS font string to a font object
  		// description:
  		//		Converts a CSS font string to a gfx font object. The CSS font
  		//		string components should follow the W3C specified order
  		//		(see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
  		//		style, variant, weight, size, optional line height (will be
  		//		ignored), and family.
  		// str: String
  		//		a CSS font string
  		var font = dojox.gfx.getDefault("Font");
  		var t = str.split(/\s+/);
  		do{
  			if(t.length < 5){ break; }
  			font.style   = t[0];
  			font.variant = t[1];
  			font.weight  = t[2];
  			var i = t[3].indexOf("/");
  			font.size = i < 0 ? t[3] : t[3].substring(0, i);
  			var j = 4;
  			if(i < 0){
  				if(t[4] == "/"){
  					j = 6;
  				}else if(t[4].charAt(0) == "/"){
  					j = 5;
  				}
  			}
  			if(j < t.length){
  				font.family = t.slice(j).join(" ");
  			}
  		}while(false);
  		return font;	// Object
  	},
  	// length operations
  	cm_in_pt: 72 / 2.54,	// Number: points per centimeter
  	mm_in_pt: 7.2 / 2.54,	// Number: points per millimeter
  	px_in_pt: function(){
  		// summary: returns a number of pixels per point
  		return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12;	// Number
  	},
  	pt2px: function(len){
  		// summary: converts points to pixels
  		// len: Number: a value in points
  		return len * dojox.gfx.px_in_pt();	// Number
  	},
  	px2pt: function(len){
  		// summary: converts pixels to points
  		// len: Number: a value in pixels
  		return len / dojox.gfx.px_in_pt();	// Number
  	},
  	normalizedLength: function(len) {
  		// summary: converts any length value to pixels
  		// len: String: a length, e.g., "12pc"
  		if(len.length == 0) return 0;
  		if(len.length > 2){
  			var px_in_pt = dojox.gfx.px_in_pt();
  			var val = parseFloat(len);
  			switch(len.slice(-2)){
  				case "px": return val;
  				case "pt": return val * px_in_pt;
  				case "in": return val * 72 * px_in_pt;
  				case "pc": return val * 12 * px_in_pt;
  				case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt;
  				case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt;
  			}
  		}
  		return parseFloat(len);	// Number
  	},
  
  	// a constant used to split a SVG/VML path into primitive components
  	pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  	pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  
  	equalSources: function(a, b){
  		// summary: compares event sources, returns true if they are equal
  		return a && b && a == b;
  	}
  });
  
  }
  
  if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojox.gfx"] = true;
  dojo.provide("dojox.gfx");
  
  
  
  
  dojo.loadInit(function(){
  	//Since loaderInit can be fired before any dojo.provide/require calls,
  	//make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer
  	//has not been defined yet.
  	var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match;
  	if(!gfx.renderer){
  		//Have a way to force a GFX renderer, if so desired.
  		//Useful for being able to serialize GFX data in a particular format.
  		if(dojo.config.forceGfxRenderer){
  			dojox.gfx.renderer = dojo.config.forceGfxRenderer;
  			return;
  		}
  		var renderers = (typeof dojo.config.gfxRenderer == "string" ?
  			dojo.config.gfxRenderer : "svg,vml,silverlight,canvas").split(",");
  
  		// mobile platform detection
  		// TODO: move to the base?
  
  		var ua = navigator.userAgent, iPhoneOsBuild = 0, androidVersion = 0;
  		if(dojo.isSafari >= 3){
  			// detect mobile version of WebKit starting with "version 3"
  
  			//	comprehensive iPhone test.  Have to figure out whether it's SVG or Canvas based on the build.
  			//	iPhone OS build numbers from en.wikipedia.org.
  			if(ua.indexOf("iPhone") >= 0 || ua.indexOf("iPod") >= 0){
  				//	grab the build out of this.  Expression is a little nasty because we want
  				//		to be sure we have the whole version string.
  				match = ua.match(/Version\/(\d(\.\d)?(\.\d)?)\sMobile\/([^\s]*)\s?/);
  				if(match){
  					//	grab the build out of the match.  Only use the first three because of specific builds.
  					iPhoneOsBuild = parseInt(match[4].substr(0,3), 16);
  				}
  			}
  		}
  		if(dojo.isWebKit){
  			// Android detection
  			if(!iPhoneOsBuild){
  				match = ua.match(/Android\s+(\d+\.\d+)/);
  				if(match){
  					androidVersion = parseFloat(match[1]);
  					// Android 1.0-1.1 doesn't support SVG but supports Canvas
  				}
  			}
  		}
  
  		for(var i = 0; i < renderers.length; ++i){
  			switch(renderers[i]){
  				case "svg":
  					//	iPhone OS builds greater than 5F1 should have SVG.
  					if(!dojo.isIE && (!iPhoneOsBuild || iPhoneOsBuild >= 0x5f1) && !androidVersion && !dojo.isAIR){
  						dojox.gfx.renderer = "svg";
  					}
  					break;
  				case "vml":
  					if(dojo.isIE){
  						dojox.gfx.renderer = "vml";
  					}
  					break;
  				case "silverlight":
  					try{
  						if(dojo.isIE){
  							sl = new ActiveXObject("AgControl.AgControl");
  							if(sl && sl.IsVersionSupported("1.0")){
  								flag = true;
  							}
  						}else{
  							if(navigator.plugins["Silverlight Plug-In"]){
  								flag = true;
  							}
  						}
  					}catch(e){
  						flag = false;
  					}finally{
  						sl = null;
  					}
  					if(flag){ dojox.gfx.renderer = "silverlight"; }
  					break;
  				case "canvas":
  					//TODO: need more comprehensive test for Canvas
  					if(!dojo.isIE){
  						dojox.gfx.renderer = "canvas";
  					}
  					break;
  			}
  			if(dojox.gfx.renderer){ break; }
  		}
  		if(dojo.config.isDebug){
  			console.log("gfx renderer = " + dojox.gfx.renderer);
  		}
  	}
  });
  
  // include a renderer conditionally
  dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg");
  dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml");
  dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight");
  dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas");
  
  }
  
  