GhostManSec
Server: Apache
System: Linux webm003.cluster115.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User: eliteafr (153088)
PHP: 5.4.45
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/eliteafr/pmb/javascript/dojo/dojo/pmbmaps.js.uncompressed.js
require({cache:{
'dojox/geo/openlayers/widget/Map':function(){
define([
	"dojo/_base/lang",
	"dojo/_base/declare",
	"dojo/_base/array",
	"dojo/dom-geometry",
	"dojo/query",
	"dijit/_Widget",
	"../_base",
	"../Map",
	"../Layer",
	"../GfxLayer"
], function(lang, declare, array, domgeo, query, Widget, openlayers, Map, Layer, GfxLayer){

	return declare("dojox.geo.openlayers.widget.Map", Widget, {
		// summary:
		//		A widget version of the `dojox.geo.openlayers.Map` component.
		// description:
		//		The `dojox.geo.openlayers.widget.Map` widget is the widget 
		//		version of the `dojox.geo.openlayers.Map` component. 
		//		With this widget, user can specify some attributes in the markup such as
		//		
		//		- `baseLayerType`: The type of the base layer. Permitted values are
		//		- `initialLocation`: The initial location as for the dojox.geo.openlayers.Map.fitTo method
		//		- `touchHandler`: Tells if we attach touch handler or not.
		//
		// example:
		//	| <div id="map" dojoType="dojox.geo.openlayers.widget.Map" baseLayerType="Google" initialLocation="{
		//	|   position: [7.154126, 43.651748],
		//	|   extent: 0.2 }"
		//	| style="background-color: #b5d0d0; width: 100%; height: 100%;">
		//

		// baseLayerType: String
		//		Base layer type as defined in `dojox.geo.openlayer.BaseLayerType`. Can be one of:
		//
		//		- `OSM`
		//		- `WMS`
		//		- `Google`
		//		- `VirtualEarth`
		//		- `Yahoo`
		//		- `ArcGIS`
		baseLayerType: openlayers.BaseLayerType.OSM,

		// initialLocation: String
		//		The part of the map shown at startup time. It is the string description of the location shown at
		//		startup time. Format is the same as for the `dojox.geo.openlayers.widget.Map.fitTo`
		//		method.
		//	|	{
		//	|		bounds: [ulx, uly, lrx, lry]
		//	|	}
		//		The map is fit on the specified bounds expressed as decimal degrees latitude and longitude.
		//		The bounds are defined with their upper left and lower right corners coordinates.
		//
		//	|	{
		//	|		position: [longitude, latitude],
		//	|		extent: degrees
		//	|	}
		//		The map is fit on the specified position showing the extent `<extent>` around
		//		the specified center position.
		initialLocation: null,

		// touchHandler: Boolean
		//		Tells if the touch handler should be attached to the map or not.
		//		Touch handler handles touch events so that the widget can be used
		//		on mobile applications.
		touchHandler: false,

		// map: [readonly] Map
		//		The underlying `dojox/geo/openlayers/Map` object.
		map : null,

		startup: function(){
			// summary:
			//		Processing after the DOM fragment is added to the document
			this.inherited(arguments);
			this.map.initialFit({
				initialLocation: this.initialLocation
			});
		},

		buildRendering: function(){
			// summary:
			//		Construct the UI for this widget, creates the real dojox.geo.openlayers.Map object.		
			// tags:
			//		protected
			this.inherited(arguments);
			var div = this.domNode;
			var map = new Map(div, {
				baseLayerType: this.baseLayerType,
				touchHandler: this.touchHandler
			});
			this.map = map;

			this._makeLayers();
		},

		_makeLayers: function(){
			// summary:
			//		Creates layers defined as markup.
			// tags:
			//		private
			var n = this.domNode;
			var layers = /* ?? query. */query("> .layer", n);
			array.forEach(layers, function(l){
				var type = l.getAttribute("type");
				var name = l.getAttribute("name");
				var cls = "dojox.geo.openlayers." + type;
				var p = lang.getObject(cls);
				if(p){
					var layer = new p(name, {});
					if(layer){
						this.map.addLayer(layer);
					}
				}
			}, this);
		},

		resize : function(b,h){
			// summary:
			//		Resize the widget.
			// description:
			//		Resize the domNode and the widget to the dimensions of a box of the following form:
			//		`{ l: 50, t: 200, w: 300: h: 150 }`
			// b: Object|Number?
			//		If passed, denotes the new size of the widget.
			//		Can be either nothing (widget adapts to the div),
			//		an Object describing a box, or a Number representing the width.
			// h: Number?
			//		The new height. Requires that a width has been specified in the first parameter.

			var olm = this.map.getOLMap();

			var box;
			switch(arguments.length){
				case 0:
					// case 0, do not resize the div, just the surface
				break;
				case 1:
					// argument, override node box
					box = lang.mixin({}, b);
					domgeo.setMarginBox(olm.div, box);
				break;
				case 2:
					// two argument, width, height
					box = {
						w: arguments[0],
						h: arguments[1]
					};
					domgeo.setMarginBox(olm.div, box);
				break;
			}
			olm.updateSize();
		}
	});
});

},
'dojox/geo/openlayers/_base':function(){
define(["dojo/_base/lang"], function(lang){
	
	var openlayers = lang.getObject("dojox.geo.openlayers", true);
	/*===== openlayers = dojox.geo.openlayers; =====*/
	
	openlayers.BaseLayerType = {
		// summary:
		//		Defines the base layer types to be used at Map construction time or
		//		with the setBaseLayerType function.
		// description:
		//		This object defines the base layer types to be used at Map construction
		//		time or with the setBaseLayerType function.

		// OSM: String
		//		The Open Street Map base layer type selector.
		OSM: "OSM",

		// Transport: String
		//		The Open Cycle Map transport layer type selector.
		Transport: "OSM.Transport",

		// WMS: String
		//		The Web Map Server base layer type selector.
		WMS: "WMS",

		// GOOGLE: String
		//		The Google base layer type selector.
		GOOGLE: "Google",

		// VIRTUAL_EARTH: String
		//		The Virtual Earth base layer type selector.
		VIRTUAL_EARTH: "VirtualEarth",

		// BING: String
		//		Same as Virtual Earth
		BING: "VirtualEarth",

		// YAHOO: String
		//		The Yahoo base layer type selector.
		YAHOO: "Yahoo",

		// ARCGIS: String
		//		The ESRI ARCGis base layer selector.
		ARCGIS: "ArcGIS"
	};

	openlayers.EPSG4326 = new OpenLayers.Projection("EPSG:4326");

	var re = /^\s*(\d{1,3})[D°]\s*(\d{1,2})[M']\s*(\d{1,2}\.?\d*)\s*(S|"|'')\s*([NSEWnsew]{0,1})\s*$/i;
	openlayers.parseDMS = function(v, toDecimal){
		// summary:
		//		Parses the specified string and returns degree minute second or decimal degree.
		// description:
		//		Parses the specified string and returns degree minute second or decimal degree.
		// v: String
		//		The string to parse
		// toDecimal: Boolean
		//		Specifies if the result should be returned in decimal degrees or in an array
		//		containing the degrees, minutes, seconds values.
		// returns: Float|Array
		//		the parsed value in decimal degrees or an array containing the degrees, minutes, seconds values.

		var res = re.exec(v);
		if(res == null || res.length < 5){
			return parseFloat(v);
		}
		var d = parseFloat(res[1]);
		var m = parseFloat(res[2]);
		var s = parseFloat(res[3]);
		var nsew = res[5];
		if(toDecimal){
			var lc = nsew.toLowerCase();
			var dd = d + (m + s / 60.0) / 60.0;
			if(lc == "w" || lc == "s"){
				dd = -dd;
			}
			return dd;
		}
		return [d, m, s, nsew];
	};
	
	return openlayers;
});

},
'dojox/geo/openlayers/Map':function(){
define([
	"dojo/_base/kernel",
	"dojo/_base/declare",
	"dojo/_base/lang",
	"dojo/_base/array",
	"dojo/_base/json",
	"dojo/dom",
	"dojo/dom-style",
	"./_base",
	"./TouchInteractionSupport",
	"./Layer",
	"./Patch"
], function(kernel, declare, lang, array, json, dom, style, openlayers, TouchInteractionSupport, Layer, Patch){

	kernel.experimental("dojox.geo.openlayers.Map");


	Patch.patchGFX();

	/*=====
	dojox.geo.openlayers.__MapArgs = {
		// summary:
		//		The keyword arguments that can be passed in a Map constructor.
		// baseLayerType: String
		//		 type of the base layer. Can be any of
		//
		//		- `dojox.geo.openlayers.BaseLayerType.OSM`: Open Street Map base layer
		//		- `dojox.geo.openlayers.BaseLayerType.Transport`: Open Street Map Transport base layer (opencyclemap.org)
		//		- `dojox.geo.openlayers.BaseLayerType.WMS`: Web Map Service layer
		//		- `dojox.geo.openlayers.BaseLayerType.GOOGLE`: Google layer
		//		- `dojox.geo.openlayers.BaseLayerType.VIRTUAL_EARTH`: Virtual Earth layer
		//		- `dojox.geo.openlayers.BaseLayerType.BING`: Bing layer
		//		- `dojox.geo.openlayers.BaseLayerType.YAHOO`: Yahoo layer
		//		- `dojox.geo.openlayers.BaseLayerType.ARCGIS`: ESRI ArgGIS layer
		// baseLayerName: String
		//		The name of the base layer.
		// baseLayerUrl: String
		//		Some layer may need an url such as Web Map Server.
		// baseLayerOptions: String
		//		Additional specific options passed to OpensLayers layer, such as The list of layer to display, for Web Map Server layer.
	};
	=====*/

	return declare("dojox.geo.openlayers.Map", null, {
		// summary:
		//		A map viewer based on the OpenLayers library.
		//
		// description:
		//		The `dojox.geo.openlayers.Map` object allows to view maps from various map providers. 
		//		It encapsulates  an `OpenLayers.Map` object on which most operations are delegated.
		//		GFX layers can be added to display GFX georeferenced shapes as well as Dojo widgets.
		//		Parameters can be passed as argument at construction time to define the base layer
		//		type and the base layer parameters such as url or options depending on the type
		//		specified. These parameters can be any of:
		//
		//		_baseLayerType_: type of the base layer. Can be any of:
		//		
		//		- `dojox.geo.openlayers.BaseLayerType.OSM`: Open Street Map base layer
		//		- `dojox.geo.openlayers.BaseLayerType.Transport`: Open Street Map Transport base layer (opencyclemap.org)
		//		- `dojox.geo.openlayers.BaseLayerType.WMS`: Web Map Service layer
		//		- `dojox.geo.openlayers.BaseLayerType.GOOGLE`: Google layer
		//		- `dojox.geo.openlayers.BaseLayerType.VIRTUAL_EARTH`: Virtual Earth layer
		//		- `dojox.geo.openlayers.BaseLayerType.BING`: Bing layer
		//		- `dojox.geo.openlayers.BaseLayerType.YAHOO`: Yahoo layer
		//		- `dojox.geo.openlayers.BaseLayerType.ARCGIS`: ESRI ArgGIS layer
		//		
		//		Note that access to commercial server such as Google, Virtual Earth or Yahoo may need specific licencing.
		//		
		//		The parameters value also include:
		//		
		//		- `baseLayerName`: The name of the base layer.
		//		- `baseLayerUrl`: Some layer may need an url such as Web Map Server
		//		- `baseLayerOptions`: Additional specific options passed to OpensLayers layer,
		//		  such as The list of layer to display, for Web Map Server layer.
		//
		// example:
		//	|	var map = new dojox.geo.openlayers.widget.Map(div, {
		//	|		baseLayerType: dojox.geo.openlayers.BaseLayerType.OSM,
		//	|		baseLayerName: 'Open Street Map Layer'
		//	|	});

		// olMap: OpenLayers.Map
		//		The underlying OpenLayers.Map object.
		//		Should be accessed on read mode only.
		olMap: null,

		_tp: null,

		constructor: function(div, options){
			// summary:
			//		Constructs a new Map object
			if(!options){
				options = {};
			}

			div = dom.byId(div);

			this._tp = {
				x: 0,
				y: 0
			};

			var opts = options.openLayersMapOptions;

			if(!opts){
				opts = {
					controls: [new OpenLayers.Control.ScaleLine({
						maxWidth: 200
					}), new OpenLayers.Control.Navigation()]
				};
			}
			if(options.accessible){
				var kbd = new OpenLayers.Control.KeyboardDefaults();
				if(!opts.controls){
					opts.controls = [];
				}
				opts.controls.push(kbd);
			}
			var baseLayerType = options.baseLayerType;
			if(!baseLayerType){
				baseLayerType = openlayers.BaseLayerType.OSM;
			}
			var map = new OpenLayers.Map(div, opts);
			this.olMap = map;

			this._layerDictionary = {
				olLayers: [],
				layers: []
			};

			if(options.touchHandler){
				this._touchControl = new TouchInteractionSupport(map);
			}

			var base = this._createBaseLayer(options);
			this.addLayer(base);

			this.initialFit(options);
		},

		initialFit: function(params){
			// summary:
			//		Performs an initial fit to contents.
			// tags:
			//		protected
			var o = params.initialLocation;
			if(!o){
				o = [-160, 70, 160, -70];
			}
			this.fitTo(o);
		},

		setBaseLayerType: function(type){
			// summary:
			//		Set the base layer type, replacing the existing base layer
			// type: dojox/geo/openlayers.BaseLayerType
			//		base layer type
			// returns:
			//		The newly created layer.
			if(type == this.baseLayerType){
				return null; // Layer
			}

			var o = null;
			if(typeof type == "string"){
				o = {
					baseLayerName: type,
					baseLayerType: type
				};
				this.baseLayerType = type;
			}else if(typeof type == "object"){
				o = type;
				this.baseLayerType = o.baseLayerType;
			}
			var bl = null;
			if(o != null){
				bl = this._createBaseLayer(o);
				if(bl != null){
					var olm = this.olMap;
					var ob = olm.getZoom();
					var oc = olm.getCenter();
					var recenter = !!oc && !!olm.baseLayer && !!olm.baseLayer.map;

					if(recenter){
						var proj = olm.getProjectionObject();
						if(proj != null){
							oc = oc.transform(proj, openlayers.EPSG4326);
						}
					}
					var old = olm.baseLayer;
					if(old != null){
						var l = this._getLayer(old);
						this.removeLayer(l);
					}
					if(bl != null){
						this.addLayer(bl);
					}
					if(recenter){
						proj = olm.getProjectionObject();
						if(proj != null){
							oc = oc.transform(openlayers.EPSG4326, proj);
						}
						olm.setCenter(oc, ob);
					}
				}
			}
			return bl;
		},

		getBaseLayerType: function(){
			// summary:
			//		Returns the base layer type.
			// returns:
			//		The current base layer type.
			return this.baseLayerType; // openlayers.BaseLayerType
		},

		getScale: function(geodesic){
			// summary:
			//		Returns the current scale
			// geodesic: Boolean
			//		Tell if geodesic calculation should be performed. If set to
			//		true, the scale will be calculated based on the horizontal size of the
			//		pixel in the center of the map viewport.
			var scale = null;
			var om = this.olMap;
			if(geodesic){
				var units = om.getUnits();
				if(!units){
					return null;	// Number
				}
				var inches = OpenLayers.INCHES_PER_UNIT;
				scale = (om.getGeodesicPixelSize().w || 0.000001) * inches["km"] * OpenLayers.DOTS_PER_INCH;
			}else{
				scale = om.getScale();
			}
			return scale;	// Number
		},

		getOLMap: function(){
			// summary:
			//		gets the underlying OpenLayers map object.
			// returns:
			//		The underlying OpenLayers map object.
			return this.olMap;	// OpenLayers.Map
		},

		_createBaseLayer: function(params){
			// summary:
			//		Creates the base layer.
			// tags:
			//		private
			var base = null;
			var type = params.baseLayerType;
			var url = params.baseLayerUrl;
			var name = params.baseLayerName;
			var options = params.baseLayerOptions;

			if(!name){
				name = type;
			}
			if(!options){
				options = {};
			}
			switch(type){
				case openlayers.BaseLayerType.OSM:
					options.transitionEffect = "resize";
					//				base = new OpenLayers.Layer.OSM(name, url, options);
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.OSM(name, url, options)
					});
				break;
				case openlayers.BaseLayerType.Transport:
					options.transitionEffect = "resize";
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.OSM.TransportMap(name, url, options)
					});
				break;
				case openlayers.BaseLayerType.WMS:
					if(!url){
						url = "http://labs.metacarta.com/wms/vmap0";
						if(!options.layers){
							options.layers = "basic";
						}
					}
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.WMS(name, url, options, {
							transitionEffect: "resize"
						})
					});
				break;
				case openlayers.BaseLayerType.GOOGLE:
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.Google(name, options)
					});
				break;
				case openlayers.BaseLayerType.VIRTUAL_EARTH:
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.VirtualEarth(name, options)
					});
				break;
				case openlayers.BaseLayerType.YAHOO:
					//				base = new OpenLayers.Layer.Yahoo(name);
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.Yahoo(name, options)
					});
				break;
				case openlayers.BaseLayerType.ARCGIS:
					if(!url){
						url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/export";
					}
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.ArcGIS93Rest(name, url, options, {})
					});

				break;
			}

			if(base == null){
				if(type instanceof OpenLayers.Layer){
					base = type;
				}else{
					options.transitionEffect = "resize";
					base = new Layer(name, {
						olLayer: new OpenLayers.Layer.OSM(name, url, options)
					});
					this.baseLayerType = openlayers.BaseLayerType.OSM;
				}
			}

			return base;
		},

		removeLayer: function(layer){
			// summary:
			//		Remove the specified layer from the map.
			// layer: Layer
			//		The layer to remove from the map.
			var om = this.olMap;
			var i = array.indexOf(this._layerDictionary.layers, layer);
			if(i > 0){
				this._layerDictionary.layers.splice(i, 1);
			}
			var oll = layer.olLayer;
			var j = array.indexOf(this._layerDictionary.olLayers, oll);
			if(j > 0){
				this._layerDictionary.olLayers.splice(i, j);
			}
			om.removeLayer(oll, false);
		},

		layerIndex: function(layer, index){
			// summary:
			//		Set or retrieve the layer index.
			// description:
			//		Set or get the layer index, that is the z-order of the layer.
			//		if the index parameter is provided, the layer index is set to
			//		this value. If the index parameter is not provided, the index of 
			//		the layer is returned.
			// layer: Layer
			//		the layer to retrieve the index.
			// index: int?
			//		index of the layer
			// returns:
			//		the index of the layer.
			var olm = this.olMap;
			if(!index){
				return olm.getLayerIndex(layer.olLayer);
			}
			//olm.raiseLayer(layer.olLayer, index);
			olm.setLayerIndex(layer.olLayer, index);

			this._layerDictionary.layers.sort(function(l1, l2){
				return olm.getLayerIndex(l1.olLayer) - olm.getLayerIndex(l2.olLayer);
			});
			this._layerDictionary.olLayers.sort(function(l1, l2){
				return olm.getLayerIndex(l1) - olm.getLayerIndex(l2);
			});

			return index; // Number
		},

		addLayer: function(layer){
			// summary:
			//		Add the specified layer to the map.
			// layer: Layer
			//		The layer to add to the map.
			layer.dojoMap = this;
			var om = this.olMap;
			var ol = layer.olLayer;
			this._layerDictionary.olLayers.push(ol);
			this._layerDictionary.layers.push(layer);
			om.addLayer(ol);
			layer.added();
		},

		_getLayer: function(/*OpenLayer.Layer */ol){
			// summary:
			//		Retrieve the dojox.geo.openlayer.Layer from the OpenLayer.Layer
			// tags:
			//		private
			var i = array.indexOf(this._layerDictionary.olLayers, ol);
			if(i != -1){
				return this._layerDictionary.layers[i];
			}
			return null;
		},

		getLayer: function(property, value){
			// summary:
			//		Returns the layer whose property matches the value.
			// property: String
			//		The property to check
			// value: Object
			//		The value to match
			// returns:
			//		The layer(s) matching the property's value. Since multiple layers
			//		match the property's value the return value is an array. 
			// example:
			//		var layers = map.getLayer("name", "Layer Name");
			var om = this.olMap;
			var ols = om.getBy("layers", property, value);
			var ret = new Array(); //[];
			array.forEach(ols, function(ol){
				ret.push(this._getLayer(ol));
			}, this);
			return ret; // Layer[]
		},

		getLayerCount: function(){
			// summary:
			//		Returns the count of layers of this map.
			// returns:
			//		The number of layers of this map. 
			var om = this.olMap;
			if(om.layers == null){
				return 0;
			}
			return om.layers.length; // Number
		},

		fitTo: function(o){
			// summary:
			//		Fits the map on a point,or an area
			// description:
			//		Fits the map on the point or extent specified as parameter. 
			// o: Object
			//		Object with key values fit parameters or a JSON string.
			// example:
			//		Examples of arguments passed to the fitTo function:
			//	|	null
			//		The map is fit on full extent
			//
			//	|	{
			//	|		bounds: [ulx, uly, lrx, lry]
			//	|	}
			//		The map is fit on the specified bounds expressed as decimal degrees latitude and longitude.
			//		The bounds are defined with their upper left and lower right corners coordinates.
			// 
			//	|	{
			//	|		position: [longitude, latitude],
			//	|		extent: degrees
			//	|	}
			//		The map is fit on the specified position showing the extent `<extent>` around
			//		the specified center position.

			var map = this.olMap;
			var from = openlayers.EPSG4326;

			if(o == null){
				var c = this.transformXY(0, 0, from);
				map.setCenter(new OpenLayers.LonLat(c.x, c.y));
				return;
			}
			var b = null;
			if(typeof o == "string"){
				var j = json.fromJson(o);
			}else{
				j = o;
			}
			var ul;
			var lr;
			if(j.hasOwnProperty("bounds")){
				var a = j.bounds;
				b = new OpenLayers.Bounds();
				ul = this.transformXY(a[0], a[1], from);
				b.left = ul.x;
				b.top = ul.y;
				lr = this.transformXY(a[2], a[3], from);
				b.right = lr.x;
				b.bottom = lr.y;
			}
			if(b == null){
				if(j.hasOwnProperty("position")){
					var p = j.position;
					var e = j.hasOwnProperty("extent") ? j.extent : 1;
					if(typeof e == "string"){
						e = parseFloat(e);
					}
					b = new OpenLayers.Bounds();
					ul = this.transformXY(p[0] - e, p[1] + e, from);
					b.left = ul.x;
					b.top = ul.y;
					lr = this.transformXY(p[0] + e, p[1] - e, from);
					b.right = lr.x;
					b.bottom = lr.y;
				}
			}
			if(b == null){
				if(o.length == 4){
					b = new OpenLayers.Bounds();
					// TODO Choose the correct method
					if(false){
						b.left = o[0];
						b.top = o[1];

						b.right = o[2];
						b.bottom = o[3];
					}else{
						ul = this.transformXY(o[0], o[1], from);
						b.left = ul.x;
						b.top = ul.y;
						lr = this.transformXY(o[2], o[3], from);
						b.right = lr.x;
						b.bottom = lr.y;
					}
				}
			}
			if(b != null){
				map.zoomToExtent(b, true);
			}
		},

		transform: function(p, from, to){
			// summary:
			//		Transforms the point passed as argument, expressed in the <em>from</em> 
			//		coordinate system to the map coordinate system.
			// description:
			//		Transforms the point passed as argument without modifying it. The point is supposed to be expressed
			//		in the <em>from</em> coordinate system and is transformed to the map coordinate system.
			// p: Object {x, y}
			//		The point to transform
			// from: OpenLayers.Projection
			//		The projection in which the point is expressed.
			return this.transformXY(p.x, p.y, from, to);
		},

		transformXY: function(x, y, from, to){
			// summary:
			//		Transforms the coordinates passed as argument, expressed in the <em>from</em> 
			//		coordinate system to the map coordinate system.
			// description:
			//		Transforms the coordinates passed as argument. The coordinate are supposed to be expressed
			//		in the <em>from</em> coordinate system and are transformed to the map coordinate system.
			// x: Number
			//		The longitude coordinate to transform.
			// y: Number
			//		The latitude coordinate to transform.
			// from: OpenLayers.Projection?
			//		The projection in which the point is expressed, or EPSG4326 is not specified.
			// to: OpenLayers.Projection?
			//		The projection in which the point is converted to. In not specifed, the map projection is used.
			// returns:
			//		The transformed coordinate as an {x,y} Object.

			var tp = this._tp;
			tp.x = x;
			tp.y = y;
			if(!from){
				from = openlayers.EPSG4326;
			}
			if(!to){
				to = this.olMap.getProjectionObject();
			}
			tp = OpenLayers.Projection.transform(tp, from, to);
			return tp; // Object
		}

	});

});

},
'dojox/geo/openlayers/TouchInteractionSupport':function(){
define([
	"dojo/_base/declare",
	"dojo/_base/connect",
	"dojo/_base/html",
	"dojo/_base/lang",
	"dojo/_base/event",
	"dojo/_base/window"
], function(declare, connect, html, lang, event, win){

	return declare("dojox.geo.openlayers.TouchInteractionSupport", null, {
		// summary:
		//		class to handle touch interactions on a OpenLayers.Map widget
		// tags:
		//		private

		_map: null,
		_centerTouchLocation: null,
		_touchMoveListener: null,
		_touchEndListener: null,
		_initialFingerSpacing: null,
		_initialScale: null,
		_tapCount: null,
		_tapThreshold: null,
		_lastTap: null,

		constructor: function(map){
			// summary:
			//		Constructs a new TouchInteractionSupport instance
			// map: OpenLayers.Map
			//		the Map widget this class provides touch navigation for.
			this._map = map;
			this._centerTouchLocation = new OpenLayers.LonLat(0, 0);

			var div = this._map.div;

			// install touch listeners
			connect.connect(div, "touchstart", this, this._touchStartHandler);
			connect.connect(div, "touchmove", this, this._touchMoveHandler);
			connect.connect(div, "touchend", this, this._touchEndHandler);

			this._tapCount = 0;
			this._lastTap = {
				x: 0,
				y: 0
			};
			this._tapThreshold = 100; // square distance in pixels

		},

		_getTouchBarycenter: function(touchEvent){
			// summary:
			//		returns the midpoint of the two first fingers (or the first finger location if only one)
			// touchEvent: TouchEvent
			//		a touch event
			// returns:
			//		the midpoint as an {x,y} object.
			// tags:
			//		private
			var touches = touchEvent.touches;
			var firstTouch = touches[0];
			var secondTouch = null;
			if(touches.length > 1){
				secondTouch = touches[1];
			}else{
				secondTouch = touches[0];
			}

			var marginBox = html.marginBox(this._map.div);

			var middleX = (firstTouch.pageX + secondTouch.pageX) / 2.0 - marginBox.l;
			var middleY = (firstTouch.pageY + secondTouch.pageY) / 2.0 - marginBox.t;

			return {
				x: middleX,
				y: middleY
			}; // Object

		},

		_getFingerSpacing: function(touchEvent){
			// summary:
			//		computes the distance between the first two fingers
			// touchEvent: Event
			//		a touch event
			// returns: float
			//		a distance. -1 if less that 2 fingers
			// tags:
			//		private
			var touches = touchEvent.touches;
			var spacing = -1;
			if(touches.length >= 2){
				var dx = (touches[1].pageX - touches[0].pageX);
				var dy = (touches[1].pageY - touches[0].pageY);
				spacing = Math.sqrt(dx * dx + dy * dy);
			}
			return spacing;
		},

		_isDoubleTap: function(touchEvent){
			// summary:
			//		checks whether the specified touchStart event is a double tap 
			//		(i.e. follows closely a previous touchStart at approximately the same location)
			// touchEvent: TouchEvent
			//		a touch event
			// returns: boolean
			//		true if this event is considered a double tap
			// tags:
			//		private
			var isDoubleTap = false;
			var touches = touchEvent.touches;
			if((this._tapCount > 0) && touches.length == 1){
				// test distance from last tap
				var dx = (touches[0].pageX - this._lastTap.x);
				var dy = (touches[0].pageY - this._lastTap.y);
				var distance = dx * dx + dy * dy;
				if(distance < this._tapThreshold){
					isDoubleTap = true;
				}else{
					this._tapCount = 0;
				}
			}
			this._tapCount++;
			this._lastTap.x = touches[0].pageX;
			this._lastTap.y = touches[0].pageY;
			setTimeout(lang.hitch(this, function(){
				this._tapCount = 0;
			}), 300);

			return isDoubleTap;
		},

		_doubleTapHandler: function(touchEvent){
			// summary:
			//		action performed on the map when a double tap was triggered 
			// touchEvent: TouchEvent
			//		a touch event
			// tags:
			//		private

			// perform a basic 2x zoom on touch
			var touches = touchEvent.touches;
			var marginBox = html.marginBox(this._map.div);
			var offX = touches[0].pageX - marginBox.l;
			var offY = touches[0].pageY - marginBox.t;
			// clicked map point before zooming
			var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(offX, offY));
			// zoom increment power
			this._map.setCenter(new OpenLayers.LonLat(mapPoint.lon, mapPoint.lat), this._map.getZoom() + 1);
		},

		_touchStartHandler: function(touchEvent){
			// summary:
			//		action performed on the map when a touch start was triggered 
			// touchEvent: Event
			//		a touch event
			// tags:
			//		private
			event.stop(touchEvent);

			// test double tap
			if(this._isDoubleTap(touchEvent)){
				this._doubleTapHandler(touchEvent);
				return;
			}

			// compute map midpoint between fingers		
			var middlePoint = this._getTouchBarycenter(touchEvent);

			this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));

			// store initial finger spacing to compute zoom later
			this._initialFingerSpacing = this._getFingerSpacing(touchEvent);

			// store initial map scale
			this._initialScale = this._map.getScale();

			// install touch move and up listeners (if not done by other fingers before)
			if(!this._touchMoveListener){
				this._touchMoveListener = connect.connect(win.global, "touchmove", this, this._touchMoveHandler);
			}
			if(!this._touchEndListener){
				this._touchEndListener = connect.connect(win.global, "touchend", this, this._touchEndHandler);
			}
		},

		_touchEndHandler: function(touchEvent){
			// summary:
			//		action performed on the map when a touch end was triggered 
			// touchEvent: Event
			//		a touch event
			// tags:
			//		private
			event.stop(touchEvent);

			var touches = touchEvent.touches;

			if(touches.length == 0){
				// disconnect listeners only when all fingers are up
				if(this._touchMoveListener){
					connect.disconnect(this._touchMoveListener);
					this._touchMoveListener = null;
				}
				if(this._touchEndListener){
					connect.disconnect(this._touchEndListener);
					this._touchEndListener = null;
				}
			}else{
				// recompute touch center
				var middlePoint = this._getTouchBarycenter(touchEvent);

				this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
			}
		},

		_touchMoveHandler: function(touchEvent){
			// summary:
			//		action performed on the map when a touch move was triggered 
			// touchEvent: Event
			//		a touch event
			// tags:
			//		private

			// prevent browser interaction
			event.stop(touchEvent);

			var middlePoint = this._getTouchBarycenter(touchEvent);

			// compute map offset
			var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
			var mapOffsetLon = mapPoint.lon - this._centerTouchLocation.lon;
			var mapOffsetLat = mapPoint.lat - this._centerTouchLocation.lat;

			// compute scale factor
			var scaleFactor = 1;
			var touches = touchEvent.touches;
			if(touches.length >= 2){
				var fingerSpacing = this._getFingerSpacing(touchEvent);
				scaleFactor = fingerSpacing / this._initialFingerSpacing;
				// weird openlayer bug: setting several times the same scale value lead to visual zoom...
				this._map.zoomToScale(this._initialScale / scaleFactor);
			}

			// adjust map center on barycenter
			var currentMapCenter = this._map.getCenter();
			this._map.setCenter(new OpenLayers.LonLat(currentMapCenter.lon - mapOffsetLon, currentMapCenter.lat
																																											- mapOffsetLat));

		}
	});
});

},
'dojox/geo/openlayers/Layer':function(){
define([
	"dojo/_base/declare", 
	"dojo/_base/lang", 
	"dojo/_base/array", 
	"dojo/_base/sniff",
	"./Feature"
], function(declare, lang, array, sniff, Feature){

		return declare("dojox.geo.openlayers.Layer", null, {
			// summary:
			//		Base layer class for dojox.geo.openlayers.Map specific layers extending OpenLayers.Layer class.
			//		This layer class accepts Features which encapsulates graphic objects to be added to the map.
			//		This layer class encapsulates an OpenLayers.Layer.
			//		This class provides Feature management such as add, remove and feature access.
			constructor: function(name, options){
				// summary:
				//		Constructs a new Layer.
				// name: String
				//		The name of the layer.
				// options: Object
				//		Options passed to the underlying OpenLayers.Layer object.

				var ol = options ? options.olLayer : null;

				if(!ol){
					ol = lang.delegate(new OpenLayers.Layer(name, options));
				}

				this.olLayer = ol;
				this._features = null;
				this.olLayer.events.register("moveend", this, lang.hitch(this, this.moveTo));
			},

			renderFeature: function(/* Feature */f){
				// summary:
				//		Called when rendering a feature is necessary.
				// f: Feature
				//		The feature to draw.
				f.render();
			},

			getDojoMap: function(){
				return this.dojoMap;
			},

			addFeature: function(f){
				// summary:
				//		Add a feature or an array of features to the layer.
				// f: Feature|Feature[]
				//		The Feature or array of features to add.
				if(lang.isArray(f)){
					array.forEach(f, function(item){
						this.addFeature(item);
					}, this);
					return;
				}
				if(this._features == null){
					this._features = [];
				}
				this._features.push(f);
				f._setLayer(this);
			},

			removeFeature: function(f){
				// summary:
				//		Removes a feature or an array of features from the layer.
				// f: Feature|Feature[]
				//		The Feature or array of features to remove.
				var ft = this._features;
				if(ft == null){
					return;
				}
				if(f instanceof Array){
					f = f.slice(0);
					array.forEach(f, function(item){
						this.removeFeature(item);
					}, this);
					return;
				}
				var i = array.indexOf(ft, f);
				if(i != -1){
					ft.splice(i, 1);
				}
				f._setLayer(null);
				f.remove();
			},

			removeFeatureAt: function(index){
				// summary:
				//		Remove the feature at the specified index.
				// index: int
				//		The index of the feature to remove.
				var ft = this._features;
				var f = ft[index];
				if(!f){
					return;
				}
				ft.splice(index, 1);
				f._setLayer(null);
				f.remove();
			},

			getFeatures: function(){
				// summary:
				//		Returns the feature hold by this layer.
				// returns:
				//		The untouched array of features hold by this layer.
				return this._features; // Feature[]
			},

			getFeatureAt: function(i){
				// summary:
				//		Returns the i-th feature of this layer.
				// i: Number
				//		The index of the feature to return.
				// returns:
				//		The i-th feature of this layer.
				if(this._features == null){
					return undefined;
				}
				return this._features[i]; // Feature
			},

			getFeatureCount: function(){
				// summary:
				//		Returns the number of the features contained by this layer.
				// returns:
				//		The number of the features contained by this layer.
				if(this._features == null){
					return 0;
				}
				return this._features.length; // Number
			},

			clear: function(){
				// summary:
				//		Removes all the features from this layer.
				var fa = this.getFeatures();
				this.removeFeature(fa);
			},

			moveTo: function(event){
				// summary:
				//		Called when the layer is panned or zoomed.
				// event: MouseEvent
				//		The event
				if(event.zoomChanged){
					if(this._features == null){
						return;
					}
					array.forEach(this._features, function(f){
						this.renderFeature(f);
					}, this);
				}
			},

			redraw: function(){
				// summary:
				//		Redraws this layer
				if(sniff.isIE){
					setTimeout(lang.hitch(this, function(){
						this.olLayer.redraw();
					}, 0));
				}else{
					this.olLayer.redraw();
				}
			},

			added: function(){
				// summary:
				//		Called when the layer is added to the map
			}

		});
	});

},
'dojox/geo/openlayers/Feature':function(){
define([
	"dojo/_base/kernel",
	"dojo/_base/declare",
	"./_base"
], function(dojo, declare, openlayers){

	return declare("dojox.geo.openlayers.Feature", null, {
		// summary:
		//		A Feature encapsulates an item so that it can be added to a Layer.
		//		This class is not attended to be used as it, but serve as a base class
		//		for specific features such as GeometryFeature which can display georeferenced 
		//		geometries and WidgetFeature which can display georeferenced widgets. 
		constructor: function(){
			// summary:
			//		Construct a new Feature
			this._layer = null;
			this._coordSys = openlayers.EPSG4326;
		},

		getCoordinateSystem: function(){
			// summary:
			//		Returns the coordinate system in which coordinates of this feature are expressed.
			// returns:
			//		The coordinate system in which coordinates of this feature are expressed.
			return this._coordSys; // OpenLayers.Projection
		},

		setCoordinateSystem: function(/* OpenLayers.Projection */cs){
			// summary:
			//		Set the coordinate system in which coordinates of this feature are expressed.
			// cs: OpenLayers.Projection
			//		The coordinate system in which coordinates of this feature are expressed.
			this._coordSys = cs;
		},

		getLayer: function(){
			// summary:
			//		Returns the Layer to which this feature belongs.
			// returns:
			//		The layer to which this feature belongs.
			return this._layer; // dojox/geo/openlayers/Layer
		},

		_setLayer: function(/* dojox/geo/openlayers/Layer */l){
			// summary:
			//		Sets the layer to which this Feature belongs
			// description:
			//		Called when the feature is added to the Layer.
			// tags:
			//		private
			this._layer = l;
		},

		render: function(){
		// summary:
		//		subclasses implements drawing specific behavior.
		},

		remove: function(){
		// summary:
		//		Subclasses implements specific behavior.
		//		Called when removed from the layer.
		},

		_getLocalXY: function(p){
			// summary:
			//		From projected coordinates to screen coordinates
			// p: Object
			//		Object with x and y fields
			// tags:
			//		private
			var x = p.x;
			var y = p.y;
			var layer = this.getLayer();
			var resolution = layer.olLayer.map.getResolution();
			var extent = layer.olLayer.getExtent();
			var rx = (x / resolution + (-extent.left / resolution));
			var ry = ((extent.top / resolution) - y / resolution);
			return [rx, ry];
		}
	});
});

},
'dojox/geo/openlayers/Patch':function(){
define([
	"dojo/_base/kernel",
	"dojo/_base/lang",	// dojo.extend getObject
	"dojo/_base/sniff",	// dojo.isIE
	"dojox/gfx",
	"dojox/gfx/shape"
], function(dojo, lang, sniff, gfx, shape){

	var dgo = lang.getObject("geo.openlayers", true, dojox);

	dgo.Patch = {

		patchMethod: function(/*Object*/type, /*String*/method, /*Function*/execBefore, /*Function*/
		execAfter){
			// summary:
			//		Patches the specified method of the given type so that the 'execBefore' (resp. 'execAfter') function is 
			//		called before (resp. after) invoking the legacy implementation.
			// description:
			//		The execBefore function is invoked with the following parameter:
			//		execBefore(method, arguments) where 'method' is the patched method name and 'arguments' the arguments received
			//		by the legacy implementation.
			//		The execAfter function is invoked with the following parameter:
			//		execBefore(method, returnValue, arguments) where 'method' is the patched method name, 'returnValue' the value
			//		returned by the legacy implementation and 'arguments' the arguments received by the legacy implementation.
			// type: Object
			//		the type to patch.
			// method: String
			//		the method name.
			// execBefore: Function
			//		the function to execute before the legacy implementation.
			// execAfter: Function
			//		the function to execute after the legacy implementation.
			// tags:
			//		private
			var old = type.prototype[method];
			type.prototype[method] = function(){
				var callee = method;
				if(execBefore){
					execBefore.call(this, callee, arguments);
				}
				var ret = old.apply(this, arguments);
				if(execAfter){
					ret = execAfter.call(this, callee, ret, arguments) || ret;
				}
				return ret;
			};
		},

		patchGFX: function(){

			var vmlFixRawNodePath = function(){
				if(!this.rawNode.path){
					this.rawNode.path = {};
				}
			};

			var vmlFixFillColors = function(){
				if(this.rawNode.fill && !this.rawNode.fill.colors){
					this.rawNode.fill.colors = {};
				}
			};
			
			if(sniff.isIE <= 8 && gfx.renderer === "vml"){
				this.patchMethod(gfx.Line, "setShape", vmlFixRawNodePath, null);
				this.patchMethod(gfx.Polyline, "setShape", vmlFixRawNodePath, null);
				this.patchMethod(gfx.Path, "setShape", vmlFixRawNodePath, null);
				
				this.patchMethod(shape.Shape, "setFill", vmlFixFillColors, null);
			}
		}
	};
	return dgo.Patch;
});

},
'dojox/gfx':function(){
define(["dojo/_base/lang", "./gfx/_base", "./gfx/renderer!"], 
  function(lang, gfxBase, renderer){
	// module:
	//		dojox/gfx
	// summary:
	//		This the root of the Dojo Graphics package
	gfxBase.switchTo(renderer);
	return gfxBase;
});

},
'dojox/gfx/_base':function(){
define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/Color", "dojo/_base/sniff", "dojo/_base/window",
	    "dojo/_base/array","dojo/dom", "dojo/dom-construct","dojo/dom-geometry"],
function(kernel, lang, Color, has, win, arr, dom, domConstruct, domGeom){
	// module:
	//		dojox/gfx
	// summary:
	//		This module contains common core Graphics API used by different graphics renderers.

	var g = lang.getObject("dojox.gfx", true),
		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
		};
		var p, oldStyle;	
		if(has("ie")){
			//	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.
			oldStyle = win.doc.documentElement.style.fontSize || "";
			if(!oldStyle){
				win.doc.documentElement.style.fontSize="100%";
			}
		}

		//		set up the measuring node.
		var div = domConstruct.create("div", {style: {
				position: "absolute",
				left: "0",
				top: "-100px",
				width: "30px",
				height: "1000em",
				borderWidth: "0",
				margin: "0",
				padding: "0",
				outline: "none",
				lineHeight: "1",
				overflow: "hidden"
			}}, win.body());

		//		do the measurements.
		for(p in heights){
			div.style.fontSize = p;
			heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
		}

		if(has("ie")){
			// Restore the font to its old style.
			win.doc.documentElement.style.fontSize = oldStyle;
		}
		win.body().removeChild(div);
		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;
		var i, box;
		if(!measuringNode){
			measuringNode = domConstruct.create("div", {style: {
				position: "absolute",
				top: "-10000px",
				left: "0",
				visibility: "hidden"
			}}, win.body());
		}
		m = measuringNode;
		// reset styles
		m.className = "";
		s = m.style;
		s.borderWidth = "0";
		s.margin = "0";
		s.padding = "0";
		s.outline = "0";
		// set new style
		if(al > 1 && style){
			for(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();
			box = {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
		}else{
			box = domGeom.getMarginBox(m);
		}
		m.innerHTML = "";
		return box;
	};

	b._computeTextLocation = function(/*g.defaultTextShape*/textShape, /*Number*/width, /*Number*/height, /*Boolean*/fixHeight) {
		var loc = {}, align = textShape.align;
		switch (align) {
			case 'end':
				loc.x = textShape.x - width;
				break;
			case 'middle':
				loc.x = textShape.x - width / 2;
				break;
			default:
				loc.x = textShape.x;
				break;
		}
		var c = fixHeight ? 0.75 : 1;
		loc.y = textShape.y - height*c; // **rough** approximation of the ascent...
		return loc;
	};
	b._computeTextBoundingBox = function(/*shape.Text*/s){
		// summary:
		//		Compute the bbox of the given shape.Text instance. Note that this method returns an
		//		approximation of the bbox, and should be used when the underlying renderer cannot provide precise metrics.
		if(!g._base._isRendered(s)){
			return {x:0, y:0, width:0, height:0};
		}
		var loc, textShape = s.getShape(),
			font = s.getFont() || g.defaultFont,
			w = s.getTextWidth(),
			h = g.normalizedLength(font.size);
		loc = b._computeTextLocation(textShape, w, h, true);
		return {
			x: loc.x,
			y: loc.y,
			width: w,
			height: h
		};
	};
	b._isRendered = function(/*Shape*/s){
		var p = s.parent;
		while(p && p.getParent){
			p = p.parent;
		}
		return p !== null;
	};

	// 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 = kernel._scopeName + "xUnique" + (++uniqueId);
		}while(dom.byId(id));
		return id;
	};

	// IE10

	var touchActionProp = has("pointer-events") ? "touchAction" : has("MSPointer") ? "msTouchAction" : null;
	b._fixMsTouchAction = touchActionProp ? function(/*dojox/gfx/shape.Surface*/surface){
		surface.rawNode.style[touchActionProp] = "none";
	} : function() {};

	/*=====
	g.Stroke = {
		// summary:
		//		A stroke defines stylistic properties that are used when drawing a path.

		// color: String
		//		The color of the stroke, default value 'black'.
		color: "black",

		// style: String
		//		The style of the stroke, one of 'solid', ... . Default value 'solid'.
		style: "solid",

		// width: Number
		//		The width of a stroke, default value 1.
		width: 1,

		// cap: String
		//		The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'.
		cap: "butt",

		// join: Number
		//		The join style to use when combining path segments. Default value 4.
		join: 4
	};
	
	g.Fill = {
		// summary:
		//		Defines how to fill a shape. Four types of fills can be used: solid, linear gradient, radial gradient and pattern.
		//		See dojox/gfx.LinearGradient, dojox/gfx.RadialGradient and dojox/gfx.Pattern respectively for more information about the properties supported by each type.
		
		// type: String?
		//		The type of fill. One of 'linear', 'radial', 'pattern' or undefined. If not specified, a solid fill is assumed.
		type:"",
		
		// color: String|dojo/Color?
		//		The color of a solid fill type.
		color:null,
		
	};
	
	g.LinearGradient = {
		// summary:
		//		An object defining the default stylistic properties used for Linear Gradient fills.
		//		Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation.

		// type: String
		//		Specifies this object is a Linear Gradient, value 'linear'
		type: "linear",

		// x1: Number
		//		The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
		x1: 0,

		// y1: Number
		//		The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
		y1: 0,

		// x2: Number
		//		The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
		x2: 100,

		// y2: Number
		//		The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
		y2: 100,

		// colors: Array
		//		An array of colors at given offsets (from the start of the line).  The start of the line is
		//		defined at offest 0 with the end of the line at offset 1.
		//		Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
		colors: []
	};
	
	g.RadialGradient = {
		// summary:
		//		Specifies the properties for RadialGradients using in fills patterns.

		// type: String
		//		Specifies this is a RadialGradient, value 'radial'
		type: "radial",

		// cx: Number
		//		The X coordinate of the center of the radial gradient, default value 0.
		cx: 0,

		// cy: Number
		//		The Y coordinate of the center of the radial gradient, default value 0.
		cy: 0,

		// r: Number
		//		The radius to the end of the radial gradient, default value 100.
		r: 100,

		// colors: Array
		//		An array of colors at given offsets (from the center of the radial gradient).
		//		The center is defined at offest 0 with the outer edge of the gradient at offset 1.
		//		Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
		colors: []
	};
	
	g.Pattern = {
		// summary:
		//		An object specifying the default properties for a Pattern using in fill operations.

		// type: String
		//		Specifies this object is a Pattern, value 'pattern'.
		type: "pattern",

		// x: Number
		//		The X coordinate of the position of the pattern, default value is 0.
		x: 0,

		// y: Number
		//		The Y coordinate of the position of the pattern, default value is 0.
		y: 0,

		// width: Number
		//		The width of the pattern image, default value is 0.
		width: 0,

		// height: Number
		//		The height of the pattern image, default value is 0.
		height: 0,

		// src: String
		//		A url specifying the image to use for the pattern.
		src: ""
	};

	g.Text = {
		//	summary:
		//		A keyword argument object defining both the text to be rendered in a VectorText shape,
		//		and specifying position, alignment, and fitting.
		//	text: String
		//		The text to be rendered.
		//	x: Number?
		//		The left coordinate for the text's bounding box.
		//	y: Number?
		//		The top coordinate for the text's bounding box.
		//	width: Number?
		//		The width of the text's bounding box.
		//	height: Number?
		//		The height of the text's bounding box.
		//	align: String?
		//		The alignment of the text, as defined in SVG. Can be "start", "end" or "middle".
		//	fitting: Number?
		//		How the text is to be fitted to the bounding box. Can be 0 (no fitting), 1 (fitting based on
		//		passed width of the bounding box and the size of the font), or 2 (fit text to the bounding box,
		//		and ignore any size parameters).
		//	leading: Number?
		//		The leading to be used between lines in the text.
		//	decoration: String?
		//		Any text decoration to be used.
	};

	g.Font = {
		// summary:
		//		An object specifying the properties for a Font used in text operations.
	
		// type: String
		//		Specifies this object is a Font, value 'font'.
		type: "font",
	
		// style: String
		//		The font style, one of 'normal', 'bold', default value 'normal'.
		style: "normal",
	
		// variant: String
		//		The font variant, one of 'normal', ... , default value 'normal'.
		variant: "normal",
	
		// weight: String
		//		The font weight, one of 'normal', ..., default value 'normal'.
		weight: "normal",
	
		// size: String
		//		The font size (including units), default value '10pt'.
		size: "10pt",
	
		// family: String
		//		The font family, one of 'serif', 'sanserif', ..., default value 'serif'.
		family: "serif"
	};

	=====*/

	lang.mixin(g, {
		// summary:
		//		defines constants, prototypes, and utility functions for the core Graphics API

		// default shapes, which are used to fill in missing parameters
		defaultPath: {
			// summary:
			//		Defines the default Path prototype object.

			// type: String
			//		Specifies this object is a Path, default value 'path'.
			type: "path", 

			// path: String
			//		The path commands. See W32C SVG 1.0 specification.
			//		Defaults to empty string value.
			path: ""
		},
		defaultPolyline: {
			// summary:
			//		Defines the default PolyLine prototype.

			// type: String
			//		Specifies this object is a PolyLine, default value 'polyline'.
			type: "polyline",

			// points: Array
			//		An array of point objects [{x:0,y:0},...] defining the default polyline's line segments. Value is an empty array [].
			points: []
		},
		defaultRect: {
			// summary:
			//		Defines the default Rect prototype.

			// type: String
			//		Specifies this default object is a type of Rect. Value is 'rect'
			type: "rect",

			// x: Number
			//		The X coordinate of the default rectangles position, value 0.
			x: 0,

			// y: Number
			//		The Y coordinate of the default rectangle's position, value 0.
			y: 0,

			// width: Number
			//		The width of the default rectangle, value 100.
			width: 100,

			// height: Number
			//		The height of the default rectangle, value 100.
			height: 100,

			// r: Number
			//		The corner radius for the default rectangle, value 0.
			r: 0
		},
		defaultEllipse: {
			// summary:
			//		Defines the default Ellipse prototype.

			// type: String
			//		Specifies that this object is a type of Ellipse, value is 'ellipse'
			type: "ellipse",

			// cx: Number
			//		The X coordinate of the center of the ellipse, default value 0.
			cx: 0,

			// cy: Number
			//		The Y coordinate of the center of the ellipse, default value 0.
			cy: 0,

			// rx: Number
			//		The radius of the ellipse in the X direction, default value 200.
			rx: 200,

			// ry: Number
			//		The radius of the ellipse in the Y direction, default value 200.
			ry: 100
		},
		defaultCircle: {
			// summary:
			//		An object defining the default Circle prototype.

			// type: String
			//		Specifies this object is a circle, value 'circle'
			type: "circle",

			// cx: Number
			//		The X coordinate of the center of the circle, default value 0.
			cx: 0,
			// cy: Number
			//		The Y coordinate of the center of the circle, default value 0.
			cy: 0,

			// r: Number
			//		The radius, default value 100.
			r: 100
		},
		defaultLine: {
			// summary:
			//		An object defining the default Line prototype.

			// type: String
			//		Specifies this is a Line, value 'line'
			type: "line",

			// x1: Number
			//		The X coordinate of the start of the line, default value 0.
			x1: 0,

			// y1: Number
			//		The Y coordinate of the start of the line, default value 0.
			y1: 0,

			// x2: Number
			//		The X coordinate of the end of the line, default value 100.
			x2: 100,

			// y2: Number
			//		The Y coordinate of the end of the line, default value 100.
			y2: 100
		},
		defaultImage: {
			// summary:
			//		Defines the default Image prototype.

			// type: String
			//		Specifies this object is an image, value 'image'.
			type: "image",

			// x: Number
			//		The X coordinate of the image's position, default value 0.
			x: 0,

			// y: Number
			//		The Y coordinate of the image's position, default value 0.
			y: 0,

			// width: Number
			//		The width of the image, default value 0.
			width: 0,

			// height: Number
			//		The height of the image, default value 0.
			height: 0,

			// src: String
			//		The src url of the image, defaults to empty string.
			src: ""
		},
		defaultText: {
			// summary:
			//		Defines the default Text prototype.

			// type: String
			//		Specifies this is a Text shape, value 'text'.
			type: "text",

			// x: Number
			//		The X coordinate of the text position, default value 0.
			x: 0,

			// y: Number
			//		The Y coordinate of the text position, default value 0.
			y: 0,

			// text: String
			//		The text to be displayed, default value empty string.
			text: "",

			// align:	String
			//		The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
			align: "start",

			// decoration: String
			//		The text decoration , one of 'none', ... . Default value 'none'.
			decoration: "none",

			// rotated: Boolean
			//		Whether the text is rotated, boolean default value false.
			rotated: false,

			// kerning: Boolean
			//		Whether kerning is used on the text, boolean default value true.
			kerning: true
		},
		defaultTextPath: {
			// summary:
			//		Defines the default TextPath prototype.

			// type: String
			//		Specifies this is a TextPath, value 'textpath'.
			type: "textpath",

			// text: String
			//		The text to be displayed, default value empty string.
			text: "",

			// align: String
			//		The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
			align: "start",

			// decoration: String
			//		The text decoration , one of 'none', ... . Default value 'none'.
			decoration: "none",

			// rotated: Boolean
			//		Whether the text is rotated, boolean default value false.
			rotated: false,

			// kerning: Boolean
			//		Whether kerning is used on the text, boolean default value true.
			kerning: true
		},

		// default stylistic attributes
		defaultStroke: {
			// summary:
			//		A stroke defines stylistic properties that are used when drawing a path.
			//		This object defines the default Stroke prototype.
			// type: String
			//		Specifies this object is a type of Stroke, value 'stroke'.
			type: "stroke",

			// color: String
			//		The color of the stroke, default value 'black'.
			color: "black",

			// style: String
			//		The style of the stroke, one of 'solid', ... . Default value 'solid'.
			style: "solid",

			// width: Number
			//		The width of a stroke, default value 1.
			width: 1,

			// cap: String
			//		The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'.
			cap: "butt",

			// join: Number
			//		The join style to use when combining path segments. Default value 4.
			join: 4
		},
		defaultLinearGradient: {
			// summary:
			//		An object defining the default stylistic properties used for Linear Gradient fills.
			//		Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation.

			// type: String
			//		Specifies this object is a Linear Gradient, value 'linear'
			type: "linear",

			// x1: Number
			//		The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
			x1: 0,

			// y1: Number
			//		The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
			y1: 0,

			// x2: Number
			//		The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
			x2: 100,

			// y2: Number
			//		The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
			y2: 100,

			// colors: Array
			//		An array of colors at given offsets (from the start of the line).  The start of the line is
			//		defined at offest 0 with the end of the line at offset 1.
			//		Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
			colors: [
				{ offset: 0, color: "black" }, { offset: 1, color: "white" }
			]
		},
		defaultRadialGradient: {
			// summary:
			//		An object specifying the default properties for RadialGradients using in fills patterns.

			// type: String
			//		Specifies this is a RadialGradient, value 'radial'
			type: "radial",

			// cx: Number
			//		The X coordinate of the center of the radial gradient, default value 0.
			cx: 0,

			// cy: Number
			//		The Y coordinate of the center of the radial gradient, default value 0.
			cy: 0,

			// r: Number
			//		The radius to the end of the radial gradient, default value 100.
			r: 100,

			// colors: Array
			//		An array of colors at given offsets (from the center of the radial gradient).
			//		The center is defined at offest 0 with the outer edge of the gradient at offset 1.
			//		Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
			colors: [
				{ offset: 0, color: "black" }, { offset: 1, color: "white" }
			]
		},
		defaultPattern: {
			// summary:
			//		An object specifying the default properties for a Pattern using in fill operations.

			// type: String
			//		Specifies this object is a Pattern, value 'pattern'.
			type: "pattern",

			// x: Number
			//		The X coordinate of the position of the pattern, default value is 0.
			x: 0,

			// y: Number
			//		The Y coordinate of the position of the pattern, default value is 0.
			y: 0,

			// width: Number
			//		The width of the pattern image, default value is 0.
			width: 0,

			// height: Number
			//		The height of the pattern image, default value is 0.
			height: 0,

			// src: String
			//		A url specifying the image to use for the pattern.
			src: ""
		},
		defaultFont: {
			// summary:
			//		An object specifying the default properties for a Font used in text operations.

			// type: String
			//		Specifies this object is a Font, value 'font'.
			type: "font",

			// style: String
			//		The font style, one of 'normal', 'bold', default value 'normal'.
			style: "normal",

			// variant: String
			//		The font variant, one of 'normal', ... , default value 'normal'.
			variant: "normal",

			// weight: String
			//		The font weight, one of 'normal', ..., default value 'normal'.
			weight: "normal",

			// size: String
			//		The font size (including units), default value '10pt'.
			size: "10pt",

			// family: String
			//		The font family, one of 'serif', 'sanserif', ..., default value 'serif'.
			family: "serif"
		},

		getDefault: (function(){
			// summary:
			//		Returns a function used to access default memoized prototype objects (see them defined above).
			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 = g[ "default" + type ];
				return new t();
			}
		})(),

		normalizeColor: function(/*dojo/Color|Array|string|Object*/ color){
			// summary:
			//		converts any legal color representation to normalized
			//		dojo/Color object
			// color:
			//		A color representation.
			return (color instanceof Color) ? color : new 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
			var x;
			if(update){
				var empty = {};
				for(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
			// returns: Object
			//      new object with new and default properties
			var i = null;
			if(!update){
				// return dojo.clone(defaults);
				return lang.delegate(defaults);
			}
			var result = {};
			for(i in defaults){
				if(!(i in result)){
					result[i] = lang.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
			//		whether to add a space before a positive number
			// returns: String
			//      the formatted value
			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. Note that the Font.size attribute is limited to numeric CSS length.
			// str: String
			//		a CSS font string.
			// returns: Object
			//      object in dojox/gfx.defaultFont format
			var font = g.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: Number
		//		points per centimeter (constant)
		cm_in_pt: 72 / 2.54,

		// mm_in_pt: Number
		//		points per millimeter (constant)
		mm_in_pt: 7.2 / 2.54,

		px_in_pt: function(){
			// summary:
			//		returns the current number of pixels per point.
			return g._base._getCachedFontMeasurements()["12pt"] / 12;	// Number
		},

		pt2px: function(len){
			// summary:
			//		converts points to pixels
			// len: Number
			//		a value in points
			return len * g.px_in_pt();	// Number
		},

		px2pt: function(len){
			// summary:
			//		converts pixels to points
			// len: Number
			//		a value in pixels
			return len / g.px_in_pt();	// Number
		},

		normalizedLength: function(len) {
			// summary:
			//		converts any length value to pixels
			// len: String
			//		a length, e.g., '12pc'
			// returns: Number
			//      pixels
			if(len.length === 0){ return 0; }
			if(len.length > 2){
				var px_in_pt = g.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 * g.mm_in_pt * px_in_pt;
					case "cm": return val * g.cm_in_pt * px_in_pt;
				}
			}
			return parseFloat(len);	// Number
		},

		// pathVmlRegExp: RegExp
		//		a constant regular expression used to split a SVG/VML path into primitive components
		// tags:
		//		private
		pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,

		// pathVmlRegExp: RegExp
		//		a constant regular expression used to split a SVG/VML path into primitive components
		// tags:
		//		private
		pathSvgRegExp: /([A-DF-Za-df-z])|([-+]?\d*[.]?\d+(?:[eE][-+]?\d+)?)/g,

		equalSources: function(a, b){
			// summary:
			//		compares event sources, returns true if they are equal
			// a: Object
			//		first event source
			// b: Object
			//		event source to compare against a
			// returns: Boolean
			//      true, if objects are truthy and the same
			return a && b && a === b;
		},

		switchTo: function(/*String|Object*/ renderer){
			// summary:
			//		switch the graphics implementation to the specified renderer.
			// renderer:
			//		Either the string name of a renderer (eg. 'canvas', 'svg, ...) or the renderer
			//		object to switch to.
			var ns = typeof renderer == "string" ? g[renderer] : renderer;
			if(ns){
				// If more options are added, update the docblock at the end of shape.js!
				arr.forEach(["Group", "Rect", "Ellipse", "Circle", "Line",
						"Polyline", "Image", "Text", "Path", "TextPath",
						"Surface", "createSurface", "fixTarget"], function(name){
					g[name] = ns[name];
				});
				if(typeof renderer == "string"){
					g.renderer = renderer;
				}else{
					arr.some(["svg","vml","canvas","canvasWithEvents","silverlight"], function(r){
						return (g.renderer = g[r] && g[r].Surface === g.Surface ? r : null);
					});
				}
			}
		}
	});
	
	/*=====
		g.createSurface = function(parentNode, width, height){
			// summary:
			//		creates a surface
			// parentNode: Node
			//		a parent node
			// width: String|Number
			//		width of surface, e.g., "100px" or 100
			// height: String|Number
			//		height of surface, e.g., "100px" or 100
			// returns: dojox/gfx.Surface
			//     newly created surface
		};
		g.fixTarget = function(){
			// tags:
			//		private
		};
	=====*/
	
	return g; // defaults object api
});

},
'dojox/gfx/renderer':function(){
define(["./_base","dojo/_base/lang", "dojo/_base/sniff", "dojo/_base/window", "dojo/_base/config"],
  function(g, lang, has, win, config){
  //>> noBuildResolver
	var currentRenderer = null;

	has.add("vml", function(global, document, element){
		element.innerHTML = "<v:shape adj=\"1\"/>";
		var supported = ("adj" in element.firstChild);
		element.innerHTML = "";
		return supported;
	});

	return {
		// summary:
		//		This module is an AMD loader plugin that loads the appropriate graphics renderer
		//		implementation based on detected environment and current configuration settings.
		
		load: function(id, require, load){
			// tags:
			//      private
			if(currentRenderer && id != "force"){
				load(currentRenderer);
				return;
			}
			var renderer = config.forceGfxRenderer,
				renderers = !renderer && (lang.isString(config.gfxRenderer) ?
					config.gfxRenderer : "svg,vml,canvas,silverlight").split(","),
				silverlightObject, silverlightFlag;

			while(!renderer && renderers.length){
				switch(renderers.shift()){
					case "svg":
						// the next test is from https://github.com/phiggins42/has.js
						if("SVGAngle" in win.global){
							renderer = "svg";
						}
						break;
					case "vml":
						if(has("vml")){
							renderer = "vml";
						}
						break;
					case "silverlight":
						try{
							if(has("ie")){
								silverlightObject = new ActiveXObject("AgControl.AgControl");
								if(silverlightObject && silverlightObject.IsVersionSupported("1.0")){
									silverlightFlag = true;
								}
							}else{
								if(navigator.plugins["Silverlight Plug-In"]){
									silverlightFlag = true;
								}
							}
						}catch(e){
							silverlightFlag = false;
						}finally{
							silverlightObject = null;
						}
						if(silverlightFlag){
							renderer = "silverlight";
						}
						break;
					case "canvas":
						if(win.global.CanvasRenderingContext2D){
							renderer = "canvas";
						}
						break;
				}
			}

			if (renderer === 'canvas' && config.canvasEvents !== false) {
				renderer = "canvasWithEvents";
			}

			if(config.isDebug){
				console.log("gfx renderer = " + renderer);
			}

			function loadRenderer(){
				require(["dojox/gfx/" + renderer], function(module){
					g.renderer = renderer;
					// memorize the renderer module
					currentRenderer = module;
					// now load it
					load(module);
				});
			}
			if(renderer == "svg" && typeof window.svgweb != "undefined"){
				window.svgweb.addOnLoad(loadRenderer);
			}else{
				loadRenderer();
			}
		}
	};
});

},
'dojox/gfx/shape':function(){
define(["./_base", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/kernel", "dojo/_base/sniff",
	"dojo/on", "dojo/_base/array", "dojo/dom-construct", "dojo/_base/Color", "./matrix" ],
	function(g, lang, declare, kernel, has, on, arr, domConstruct, Color, matrixLib){

	var shape = g.shape = {
		// summary:
		//		This module contains the core graphics Shape API.
		//		Different graphics renderer implementation modules (svg, canvas, vml, silverlight, etc.) extend this
		//		basic api to provide renderer-specific implementations for each shape.
	};

	shape.Shape = declare("dojox.gfx.shape.Shape", null, {
		// summary:
		//		a Shape object, which knows how to apply
		//		graphical attributes and transformations
	
		constructor: function(){
			// rawNode: Node
			//		underlying graphics-renderer-specific implementation object (if applicable)
			this.rawNode = null;

			// shape: Object
			//		an abstract shape object
			//		(see dojox/gfx.defaultPath,
			//		dojox/gfx.defaultPolyline,
			//		dojox/gfx.defaultRect,
			//		dojox/gfx.defaultEllipse,
			//		dojox/gfx.defaultCircle,
			//		dojox/gfx.defaultLine,
			//		or dojox/gfx.defaultImage)
			this.shape = null;
	
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a transformation matrix
			this.matrix = null;
	
			// fillStyle: dojox/gfx.Fill
			//		a fill object
			//		(see dojox/gfx.defaultLinearGradient,
			//		dojox/gfx.defaultRadialGradient,
			//		dojox/gfx.defaultPattern,
			//		or dojo/Color)
			this.fillStyle = null;
	
			// strokeStyle: dojox/gfx.Stroke
			//		a stroke object
			//		(see dojox/gfx.defaultStroke)
			this.strokeStyle = null;
	
			// bbox: dojox/gfx.Rectangle
			//		a bounding box of this shape
			//		(see dojox/gfx.defaultRect)
			this.bbox = null;
	
			// virtual group structure
	
			// parent: Object
			//		a parent or null
			//		(see dojox/gfx/shape.Surface,
			//		or dojox/gfx.Group)
			this.parent = null;
	
			// parentMatrix: dojox/gfx/matrix.Matrix2D
			//		a transformation matrix inherited from the parent
			this.parentMatrix = null;

			if(has("gfxRegistry")){
				var uid = shape.register(this);
				this.getUID = function(){
					return uid;
				}
			}
		},
		
		destroy: function(){
			// summary:
			//		Releases all internal resources owned by this shape. Once this method has been called,
			//		the instance is considered destroyed and should not be used anymore.
			if(has("gfxRegistry")){
				shape.dispose(this);
			}
			if(this.rawNode && "__gfxObject__" in this.rawNode){
				this.rawNode.__gfxObject__ = null;
			}
			this.rawNode = null;
		},
	
		// trivial getters
	
		getNode: function(){
			// summary:
			//		Different graphics rendering subsystems implement shapes in different ways.  This
			//		method provides access to the underlying graphics subsystem object.  Clients calling this
			//		method and using the return value must be careful not to try sharing or using the underlying node
			//		in a general way across renderer implementation.
			//		Returns the underlying graphics Node, or null if no underlying graphics node is used by this shape.
			return this.rawNode; // Node
		},
		getShape: function(){
			// summary:
			//		returns the current Shape object or null
			//		(see dojox/gfx.defaultPath,
			//		dojox/gfx.defaultPolyline,
			//		dojox/gfx.defaultRect,
			//		dojox/gfx.defaultEllipse,
			//		dojox/gfx.defaultCircle,
			//		dojox/gfx.defaultLine,
			//		or dojox/gfx.defaultImage)
			return this.shape; // Object
		},
		getTransform: function(){
			// summary:
			//		Returns the current transformation matrix applied to this Shape or null
			return this.matrix;	// dojox/gfx/matrix.Matrix2D
		},
		getFill: function(){
			// summary:
			//		Returns the current fill object or null
			//		(see dojox/gfx.defaultLinearGradient,
			//		dojox/gfx.defaultRadialGradient,
			//		dojox/gfx.defaultPattern,
			//		or dojo/Color)
			return this.fillStyle;	// Object
		},
		getStroke: function(){
			// summary:
			//		Returns the current stroke object or null
			//		(see dojox/gfx.defaultStroke)
			return this.strokeStyle;	// Object
		},
		getParent: function(){
			// summary:
			//		Returns the parent Shape, Group or null if this Shape is unparented.
			//		(see dojox/gfx/shape.Surface,
			//		or dojox/gfx.Group)
			return this.parent;	// Object
		},
		getBoundingBox: function(){
			// summary:
			//		Returns the bounding box Rectangle for this shape or null if a BoundingBox cannot be
			//		calculated for the shape on the current renderer or for shapes with no geometric area (points).
			//		A bounding box is a rectangular geometric region
			//		defining the X and Y extent of the shape.
			//		(see dojox/gfx.defaultRect)
			//		Note that this method returns a direct reference to the attribute of this instance. Therefore you should
			//		not modify its value directly but clone it instead.
			return this.bbox;	// dojox/gfx.Rectangle
		},
		getTransformedBoundingBox: function(){
			// summary:
			//		returns an array of four points or null
			//		four points represent four corners of the untransformed bounding box
			var b = this.getBoundingBox();
			if(!b){
				return null;	// null
			}
			var m = this._getRealMatrix(),
				gm = matrixLib;
			return [	// Array
					gm.multiplyPoint(m, b.x, b.y),
					gm.multiplyPoint(m, b.x + b.width, b.y),
					gm.multiplyPoint(m, b.x + b.width, b.y + b.height),
					gm.multiplyPoint(m, b.x, b.y + b.height)
				];
		},
		getEventSource: function(){
			// summary:
			//		returns a Node, which is used as
			//		a source of events for this shape
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			return this.rawNode;	// Node
		},
	
		// empty settings
		
		setClip: function(clip){
			// summary:
			//		sets the clipping area of this shape.
			// description:
			//		The clipping area defines the shape area that will be effectively visible. Everything that
			//		would be drawn outside of the clipping area will not be rendered.
			//		The possible clipping area types are rectangle, ellipse, polyline and path, but all are not
			//		supported by all the renderers. vml only supports rectangle clipping, while the gfx silverlight renderer does not
			//		support path clipping.
			//		The clip parameter defines the clipping area geometry, and should be an object with the following properties:
			//
			//		- {x:Number, y:Number, width:Number, height:Number} for rectangular clip
			//		- {cx:Number, cy:Number, rx:Number, ry:Number} for ellipse clip
			//		- {points:Array} for polyline clip
			//		- {d:String} for a path clip.
			//
			//		The clip geometry coordinates are expressed in the coordinate system used to draw the shape. In other
			//		words, the clipping area is defined in the shape parent coordinate system and the shape transform is automatically applied.
			// example:
			//		The following example shows how to clip a gfx image with all the possible clip geometry: a rectangle,
			//		an ellipse, a circle (using the ellipse geometry), a polyline and a path:
			//
			//	|	surface.createImage({src:img, width:200,height:200}).setClip({x:10,y:10,width:50,height:50});
			//	|	surface.createImage({src:img, x:100,y:50,width:200,height:200}).setClip({cx:200,cy:100,rx:20,ry:30});
			//	|	surface.createImage({src:img, x:0,y:350,width:200,height:200}).setClip({cx:100,cy:425,rx:60,ry:60});
			//	|	surface.createImage({src:img, x:300,y:0,width:200,height:200}).setClip({points:[350,0,450,50,380,130,300,110]});
			//	|	surface.createImage({src:img, x:300,y:350,width:200,height:200}).setClip({d:"M 350,350 C314,414 317,557 373,450.0000 z"});

			// clip: Object
			//		an object that defines the clipping geometry, or null to remove clip.
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			this.clip = clip;
		},
		
		getClip: function(){
			return this.clip;
		},
	
		setShape: function(shape){
			// summary:
			//		sets a shape object
			//		(the default implementation simply ignores it)
			// shape: Object
			//		a shape object
			//		(see dojox/gfx.defaultPath,
			//		dojox/gfx.defaultPolyline,
			//		dojox/gfx.defaultRect,
			//		dojox/gfx.defaultEllipse,
			//		dojox/gfx.defaultCircle,
			//		dojox/gfx.defaultLine,
			//		or dojox/gfx.defaultImage)
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			this.shape = g.makeParameters(this.shape, shape);
			this.bbox = null;
			return this;	// self
		},
		setFill: function(fill){
			// summary:
			//		sets a fill object
			//		(the default implementation simply ignores it)
			// fill: Object
			//		a fill object
			//		(see dojox/gfx.defaultLinearGradient,
			//		dojox/gfx.defaultRadialGradient,
			//		dojox/gfx.defaultPattern,
			//		or dojo/_base/Color)
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			if(!fill){
				// don't fill
				this.fillStyle = null;
				return this;	// self
			}
			var f = null;
			if(typeof(fill) == "object" && "type" in fill){
				// gradient or pattern
				switch(fill.type){
					case "linear":
						f = g.makeParameters(g.defaultLinearGradient, fill);
						break;
					case "radial":
						f = g.makeParameters(g.defaultRadialGradient, fill);
						break;
					case "pattern":
						f = g.makeParameters(g.defaultPattern, fill);
						break;
				}
			}else{
				// color object
				f = g.normalizeColor(fill);
			}
			this.fillStyle = f;
			return this;	// self
		},
		setStroke: function(stroke){
			// summary:
			//		sets a stroke object
			//		(the default implementation simply ignores it)
			// stroke: Object
			//		a stroke object
			//		(see dojox/gfx.defaultStroke)
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			if(!stroke){
				// don't stroke
				this.strokeStyle = null;
				return this;	// self
			}
			// normalize the stroke
			if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
				stroke = {color: stroke};
			}
			var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
			s.color = g.normalizeColor(s.color);
			return this;	// self
		},
		setTransform: function(matrix){
			// summary:
			//		sets a transformation matrix
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a matrix or a matrix-like object
			//		(see an argument of dojox/gfx/matrix.Matrix2D
			//		constructor for a list of acceptable arguments)
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			this.matrix = matrixLib.clone(matrix ? matrixLib.normalize(matrix) : matrixLib.identity);
			return this._applyTransform();	// self
		},
	
		_applyTransform: function(){
			// summary:
			//		physically sets a matrix
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			return this;	// self
		},
	
		// z-index
	
		moveToFront: function(){
			// summary:
			//		moves a shape to front of its parent's list of shapes
			var p = this.getParent();
			if(p){
				p._moveChildToFront(this);
				this._moveToFront();	// execute renderer-specific action
			}
			return this;	// self
		},
		moveToBack: function(){
			// summary:
			//		moves a shape to back of its parent's list of shapes
			var p = this.getParent();
			if(p){
				p._moveChildToBack(this);
				this._moveToBack();	// execute renderer-specific action
			}
			return this;
		},
		_moveToFront: function(){
			// summary:
			//		renderer-specific hook, see dojox/gfx/shape.Shape.moveToFront()
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
		},
		_moveToBack: function(){
			// summary:
			//		renderer-specific hook, see dojox/gfx/shape.Shape.moveToFront()
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
		},
	
		// apply left & right transformation
	
		applyRightTransform: function(matrix){
			// summary:
			//		multiplies the existing matrix with an argument on right side
			//		(this.matrix * matrix)
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a matrix or a matrix-like object
			//		(see an argument of dojox/gfx/matrix.Matrix2D
			//		constructor for a list of acceptable arguments)
			return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
		},
		applyLeftTransform: function(matrix){
			// summary:
			//		multiplies the existing matrix with an argument on left side
			//		(matrix * this.matrix)
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a matrix or a matrix-like object
			//		(see an argument of dojox/gfx/matrix.Matrix2D
			//		constructor for a list of acceptable arguments)
			return matrix ? this.setTransform([matrix, this.matrix]) : this;	// self
		},
		applyTransform: function(matrix){
			// summary:
			//		a shortcut for dojox/gfx/shape.Shape.applyRightTransform
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a matrix or a matrix-like object
			//		(see an argument of dojox/gfx/matrix.Matrix2D
			//		constructor for a list of acceptable arguments)
			return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
		},
	
		// virtual group methods
	
		removeShape: function(silently){
			// summary:
			//		removes the shape from its parent's list of shapes
			// silently: Boolean
			//		if true, do not redraw a picture yet
			if(this.parent){
				this.parent.remove(this, silently);
			}
			return this;	// self
		},
		_setParent: function(parent, matrix){
			// summary:
			//		sets a parent
			// parent: Object
			//		a parent or null
			//		(see dojox/gfx/shape.Surface,
			//		or dojox/gfx.Group)
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a 2D matrix or a matrix-like object
			this.parent = parent;
			return this._updateParentMatrix(matrix);	// self
		},
		_updateParentMatrix: function(matrix){
			// summary:
			//		updates the parent matrix with new matrix
			// matrix: dojox/gfx/Matrix2D
			//		a 2D matrix or a matrix-like object
			this.parentMatrix = matrix ? matrixLib.clone(matrix) : null;
			return this._applyTransform();	// self
		},
		_getRealMatrix: function(){
			// summary:
			//		returns the cumulative ('real') transformation matrix
			//		by combining the shape's matrix with its parent's matrix
			var m = this.matrix;
			var p = this.parent;
			while(p){
				if(p.matrix){
					m = matrixLib.multiply(p.matrix, m);
				}
				p = p.parent;
			}
			return m;	// dojox/gfx/matrix.Matrix2D
		}
	});
	
	shape._eventsProcessing = {
		on: function(type, listener){
			//	summary:
			//		Connects an event to this shape.

			return on(this.getEventSource(), type, shape.fixCallback(this, g.fixTarget, listener));
		},

		connect: function(name, object, method){
			// summary:
			//		connects a handler to an event on this shape
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
			// redirect to fixCallback to normalize events and add the gfxTarget to the event. The latter
			// is done by dojox/gfx.fixTarget which is defined by each renderer
			if(name.substring(0, 2) == "on"){
				name = name.substring(2);
			}
			return this.on(name, method ? lang.hitch(object, method) : object);
		},

		disconnect: function(token){
			// summary:
			//		connects a handler by token from an event on this shape
			
			// COULD BE RE-IMPLEMENTED BY THE RENDERER!
	
			return token.remove();
		}
	};
	
	shape.fixCallback = function(gfxElement, fixFunction, scope, method){
		// summary:
		//		Wraps the callback to allow for tests and event normalization
		//		before it gets invoked. This is where 'fixTarget' is invoked.
		// tags:
		//      private
		// gfxElement: Object
		//		The GFX object that triggers the action (ex.:
		//		dojox/gfx.Surface and dojox/gfx/shape.Shape). A new event property
		//		'gfxTarget' is added to the event to reference this object.
		//		for easy manipulation of GFX objects by the event handlers.
		// fixFunction: Function
		//		The function that implements the logic to set the 'gfxTarget'
		//		property to the event. It should be 'dojox/gfx.fixTarget' for
		//		most of the cases
		// scope: Object
		//		Optional. The scope to be used when invoking 'method'. If
		//		omitted, a global scope is used.
		// method: Function|String
		//		The original callback to be invoked.
		if(!method){
			method = scope;
			scope = null;
		}
		if(lang.isString(method)){
			scope = scope || kernel.global;
			if(!scope[method]){ throw(['dojox.gfx.shape.fixCallback: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
			return function(e){  
				return fixFunction(e,gfxElement) ? scope[method].apply(scope, arguments || []) : undefined; }; // Function
		}
		return !scope 
			? function(e){ 
				return fixFunction(e,gfxElement) ? method.apply(scope, arguments) : undefined; } 
			: function(e){ 
				return fixFunction(e,gfxElement) ? method.apply(scope, arguments || []) : undefined; }; // Function
	};
	lang.extend(shape.Shape, shape._eventsProcessing);
	
	shape.Container = {
		// summary:
		//		a container of shapes, which can be used
		//		as a foundation for renderer-specific groups, or as a way
		//		to logically group shapes (e.g, to propagate matricies)
	
		_init: function() {
			// children: Array
			//		a list of children
			this.children = [];
			this._batch = 0;
		},
	
		// group management
	
		openBatch: function() {
			// summary:
			//		starts a new batch, subsequent new child shapes will be held in
			//		the batch instead of appending to the container directly.
			// description:
			//		Because the canvas renderer has no DOM hierarchy, the canvas implementation differs
			//		such that it suspends the repaint requests for this container until the current batch is closed by a call to closeBatch().
			return this;
		},
		closeBatch: function() {
			// summary:
			//		submits the current batch, append all pending child shapes to DOM
			// description:
			//		On canvas, this method flushes the pending redraws queue.
			return this;
		},
		add: function(shape){
			// summary:
			//		adds a shape to the list
			// shape: dojox/gfx/shape.Shape
			//		the shape to add to the list
			var oldParent = shape.getParent();
			if(oldParent){
				oldParent.remove(shape, true);
			}
			this.children.push(shape);
			return shape._setParent(this, this._getRealMatrix());	// self
		},
		remove: function(shape, silently){
			// summary:
			//		removes a shape from the list
			// shape: dojox/gfx/shape.Shape
			//		the shape to remove
			// silently: Boolean
			//		if true, do not redraw a picture yet
			for(var i = 0; i < this.children.length; ++i){
				if(this.children[i] == shape){
					if(silently){
						// skip for now
					}else{
						shape.parent = null;
						shape.parentMatrix = null;
					}
					this.children.splice(i, 1);
					break;
				}
			}
			return this;	// self
		},
		clear: function(/*Boolean?*/ destroy){
			// summary:
			//		removes all shapes from a group/surface.
			// destroy: Boolean
			//		Indicates whether the children should be destroyed. Optional.
			var shape;
			for(var i = 0; i < this.children.length;++i){
				shape = this.children[i];
				shape.parent = null;
				shape.parentMatrix = null;
				if(destroy){
					shape.destroy();
				}
			}
			this.children = [];
			return this;	// self
		},
		getBoundingBox: function(){
			// summary:
			//		Returns the bounding box Rectangle for this shape.
			if(this.children){
				// if this is a composite shape, then sum up all the children
				var result = null;
				arr.forEach(this.children, function(shape){
					var bb = shape.getBoundingBox();
					if(bb){
						var ct = shape.getTransform();
						if(ct){
							bb = matrixLib.multiplyRectangle(ct, bb);
						}
						if(result){
							// merge two bbox 
							result.x = Math.min(result.x, bb.x);
							result.y = Math.min(result.y, bb.y);
							result.endX = Math.max(result.endX, bb.x + bb.width);
							result.endY = Math.max(result.endY, bb.y + bb.height);
						}else{
							// first bbox 
							result = {
								x: bb.x,
								y: bb.y,
								endX: bb.x + bb.width,
								endY: bb.y + bb.height
							};
						}
					}
				});
				if(result){
					result.width = result.endX - result.x;
					result.height = result.endY - result.y;
				}
				return result; // dojox/gfx.Rectangle
			}
			// unknown/empty bounding box, subclass shall override this impl 
			return null;
		},
		// moving child nodes
		_moveChildToFront: function(shape){
			// summary:
			//		moves a shape to front of the list of shapes
			// shape: dojox/gfx/shape.Shape
			//		one of the child shapes to move to the front
			for(var i = 0; i < this.children.length; ++i){
				if(this.children[i] == shape){
					this.children.splice(i, 1);
					this.children.push(shape);
					break;
				}
			}
			return this;	// self
		},
		_moveChildToBack: function(shape){
			// summary:
			//		moves a shape to back of the list of shapes
			// shape: dojox/gfx/shape.Shape
			//		one of the child shapes to move to the front
			for(var i = 0; i < this.children.length; ++i){
				if(this.children[i] == shape){
					this.children.splice(i, 1);
					this.children.unshift(shape);
					break;
				}
			}
			return this;	// self
		}
	};

	shape.Surface = declare("dojox.gfx.shape.Surface", null, {
		// summary:
		//		a surface object to be used for drawings
		constructor: function(){
			// underlying node
			this.rawNode = null;
			// the parent node
			this._parent = null;
			// the list of DOM nodes to be deleted in the case of destruction
			this._nodes = [];
			// the list of events to be detached in the case of destruction
			this._events = [];
		},
		destroy: function(){
			// summary:
			//		destroy all relevant external resources and release all
			//		external references to make this object garbage-collectible
			arr.forEach(this._nodes, domConstruct.destroy);
			this._nodes = [];
			arr.forEach(this._events, function(h){ if(h){ h.remove(); } });
			this._events = [];
			this.rawNode = null;	// recycle it in _nodes, if it needs to be recycled
			if(has("ie")){
				while(this._parent.lastChild){
					domConstruct.destroy(this._parent.lastChild);
				}
			}else{
				this._parent.innerHTML = "";
			}
			this._parent = null;
		},
		getEventSource: function(){
			// summary:
			//		returns a node, which can be used to attach event listeners
			return this.rawNode; // Node
		},
		_getRealMatrix: function(){
			// summary:
			//		always returns the identity matrix
			return null;	// dojox/gfx/Matrix2D
		},
		/*=====
		 setDimensions: function(width, height){
			 // summary:
			 //		sets the width and height of the rawNode
			 // width: String
			 //		width of surface, e.g., "100px"
			 // height: String
			 //		height of surface, e.g., "100px"
			 return this;	// self
		 },
		 getDimensions: function(){
			 // summary:
			 //     gets current width and height in pixels
			 // returns: Object
			 //     object with properties "width" and "height"
		 },
		 =====*/
		isLoaded: true,
		onLoad: function(/*dojox/gfx/shape.Surface*/ surface){
			// summary:
			//		local event, fired once when the surface is created
			//		asynchronously, used only when isLoaded is false, required
			//		only for Silverlight.
		},
		whenLoaded: function(/*Object|Null*/ context, /*Function|String*/ method){
			var f = lang.hitch(context, method);
			if(this.isLoaded){
				f(this);
			}else{
				on.once(this, "load", function(surface){
					f(surface);
				});
			}
		}
	});
	lang.extend(shape.Surface, shape._eventsProcessing);

	/*=====
	g.Point = declare("dojox/gfx.Point", null, {
		// summary:
		//		2D point for drawings - {x, y}
		// description:
		//		Do not use this object directly!
		//		Use the naked object instead: {x: 1, y: 2}.
	});

	g.Rectangle = declare("dojox.gfx.Rectangle", null, {
		// summary:
		//		rectangle - {x, y, width, height}
		// description:
		//		Do not use this object directly!
		//		Use the naked object instead: {x: 1, y: 2, width: 100, height: 200}.
	});
	 =====*/


	shape.Rect = declare("dojox.gfx.shape.Rect", shape.Shape, {
		// summary:
		//		a generic rectangle
		constructor: function(rawNode){
			// rawNode: Node
			//		The underlying graphics system object (typically a DOM Node)
			this.shape = g.getDefault("Rect");
			this.rawNode = rawNode;
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box (its shape in this case)
			return this.shape;	// dojox/gfx.Rectangle
		}
	});
	
	shape.Ellipse = declare("dojox.gfx.shape.Ellipse", shape.Shape, {
		// summary:
		//		a generic ellipse
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.shape = g.getDefault("Ellipse");
			this.rawNode = rawNode;
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box
			if(!this.bbox){
				var shape = this.shape;
				this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry,
					width: 2 * shape.rx, height: 2 * shape.ry};
			}
			return this.bbox;	// dojox/gfx.Rectangle
		}
	});
	
	shape.Circle = declare("dojox.gfx.shape.Circle", shape.Shape, {
		// summary:
		//		a generic circle
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.shape = g.getDefault("Circle");
			this.rawNode = rawNode;
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box
			if(!this.bbox){
				var shape = this.shape;
				this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r,
					width: 2 * shape.r, height: 2 * shape.r};
			}
			return this.bbox;	// dojox/gfx.Rectangle
		}
	});
	
	shape.Line = declare("dojox.gfx.shape.Line", shape.Shape, {
		// summary:
		//		a generic line (do not instantiate it directly)
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.shape = g.getDefault("Line");
			this.rawNode = rawNode;
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box
			if(!this.bbox){
				var shape = this.shape;
				this.bbox = {
					x:		Math.min(shape.x1, shape.x2),
					y:		Math.min(shape.y1, shape.y2),
					width:	Math.abs(shape.x2 - shape.x1),
					height:	Math.abs(shape.y2 - shape.y1)
				};
			}
			return this.bbox;	// dojox/gfx.Rectangle
		}
	});
	
	shape.Polyline = declare("dojox.gfx.shape.Polyline", shape.Shape, {
		// summary:
		//		a generic polyline/polygon (do not instantiate it directly)
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.shape = g.getDefault("Polyline");
			this.rawNode = rawNode;
		},
		setShape: function(points, closed){
			// summary:
			//		sets a polyline/polygon shape object
			// points: Object|Array
			//		a polyline/polygon shape object, or an array of points
			// closed: Boolean
			//		close the polyline to make a polygon
			if(points && points instanceof Array){
				this.inherited(arguments, [{points: points}]);
				if(closed && this.shape.points.length){
					this.shape.points.push(this.shape.points[0]);
				}
			}else{
				this.inherited(arguments, [points]);
			}
			return this;	// self
		},
		_normalizePoints: function(){
			// summary:
			//		normalize points to array of {x:number, y:number}
			var p = this.shape.points, l = p && p.length;
			if(l && typeof p[0] == "number"){
				var points = [];
				for(var i = 0; i < l; i += 2){
					points.push({x: p[i], y: p[i + 1]});
				}
				this.shape.points = points;
			}
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box
			if(!this.bbox && this.shape.points.length){
				var p = this.shape.points;
				var l = p.length;
				var t = p[0];
				var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
				for(var i = 1; i < l; ++i){
					t = p[i];
					if(bbox.l > t.x) bbox.l = t.x;
					if(bbox.r < t.x) bbox.r = t.x;
					if(bbox.t > t.y) bbox.t = t.y;
					if(bbox.b < t.y) bbox.b = t.y;
				}
				this.bbox = {
					x:		bbox.l,
					y:		bbox.t,
					width:	bbox.r - bbox.l,
					height:	bbox.b - bbox.t
				};
			}
			return this.bbox;	// dojox/gfx.Rectangle
		}
	});
	
	shape.Image = declare("dojox.gfx.shape.Image", shape.Shape, {
		// summary:
		//		a generic image (do not instantiate it directly)
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.shape = g.getDefault("Image");
			this.rawNode = rawNode;
		},
		getBoundingBox: function(){
			// summary:
			//		returns the bounding box (its shape in this case)
			return this.shape;	// dojox/gfx.Rectangle
		},
		setStroke: function(){
			// summary:
			//		ignore setting a stroke style
			return this;	// self
		},
		setFill: function(){
			// summary:
			//		ignore setting a fill style
			return this;	// self
		}
	});
	
	shape.Text = declare(shape.Shape, {
		// summary:
		//		a generic text (do not instantiate it directly)
		constructor: function(rawNode){
			// rawNode: Node
			//		a DOM Node
			this.fontStyle = null;
			this.shape = g.getDefault("Text");
			this.rawNode = rawNode;
		},
		getFont: function(){
			// summary:
			//		returns the current font object or null
			return this.fontStyle;	// Object
		},
		setFont: function(newFont){
			// summary:
			//		sets a font for text
			// newFont: Object
			//		a font object (see dojox/gfx.defaultFont) or a font string
			this.fontStyle = typeof newFont == "string" ? g.splitFontString(newFont) :
				g.makeParameters(g.defaultFont, newFont);
			this._setFont();
			return this;	// self
		},
		getBoundingBox: function(){
			var bbox = null, s = this.getShape();
			if(s.text){
				bbox = g._base._computeTextBoundingBox(this);
			}
			return bbox;
		}
	});
	
	shape.Creator = {
		// summary:
		//		shape creators
		createShape: function(shape){
			// summary:
			//		creates a shape object based on its type; it is meant to be used
			//		by group-like objects
			// shape: Object
			//		a shape descriptor object
			// returns: dojox/gfx/shape.Shape | Null
			//      a fully instantiated surface-specific Shape object
			switch(shape.type){
				case g.defaultPath.type:		return this.createPath(shape);
				case g.defaultRect.type:		return this.createRect(shape);
				case g.defaultCircle.type:	    return this.createCircle(shape);
				case g.defaultEllipse.type:	    return this.createEllipse(shape);
				case g.defaultLine.type:		return this.createLine(shape);
				case g.defaultPolyline.type:	return this.createPolyline(shape);
				case g.defaultImage.type:		return this.createImage(shape);
				case g.defaultText.type:		return this.createText(shape);
				case g.defaultTextPath.type:	return this.createTextPath(shape);
			}
			return null;
		},
		createGroup: function(){
			// summary:
			//		creates a group shape
			return this.createObject(g.Group);	// dojox/gfx/Group
		},
		createRect: function(rect){
			// summary:
			//		creates a rectangle shape
			// rect: Object
			//		a path object (see dojox/gfx.defaultRect)
			return this.createObject(g.Rect, rect);	// dojox/gfx/shape.Rect
		},
		createEllipse: function(ellipse){
			// summary:
			//		creates an ellipse shape
			// ellipse: Object
			//		an ellipse object (see dojox/gfx.defaultEllipse)
			return this.createObject(g.Ellipse, ellipse);	// dojox/gfx/shape.Ellipse
		},
		createCircle: function(circle){
			// summary:
			//		creates a circle shape
			// circle: Object
			//		a circle object (see dojox/gfx.defaultCircle)
			return this.createObject(g.Circle, circle);	// dojox/gfx/shape.Circle
		},
		createLine: function(line){
			// summary:
			//		creates a line shape
			// line: Object
			//		a line object (see dojox/gfx.defaultLine)
			return this.createObject(g.Line, line);	// dojox/gfx/shape.Line
		},
		createPolyline: function(points){
			// summary:
			//		creates a polyline/polygon shape
			// points: Object
			//		a points object (see dojox/gfx.defaultPolyline)
			//		or an Array of points
			return this.createObject(g.Polyline, points);	// dojox/gfx/shape.Polyline
		},
		createImage: function(image){
			// summary:
			//		creates a image shape
			// image: Object
			//		an image object (see dojox/gfx.defaultImage)
			return this.createObject(g.Image, image);	// dojox/gfx/shape.Image
		},
		createText: function(text){
			// summary:
			//		creates a text shape
			// text: Object
			//		a text object (see dojox/gfx.defaultText)
			return this.createObject(g.Text, text);	// dojox/gfx/shape.Text
		},
		createPath: function(path){
			// summary:
			//		creates a path shape
			// path: Object
			//		a path object (see dojox/gfx.defaultPath)
			return this.createObject(g.Path, path);	// dojox/gfx/shape.Path
		},
		createTextPath: function(text){
			// summary:
			//		creates a text shape
			// text: Object
			//		a textpath object (see dojox/gfx.defaultTextPath)
			return this.createObject(g.TextPath, {}).setText(text);	// dojox/gfx/shape.TextPath
		},
		createObject: function(shapeType, rawShape){
			// summary:
			//		creates an instance of the passed shapeType class
			// shapeType: Function
			//		a class constructor to create an instance of
			// rawShape: Object 
			//		properties to be passed in to the classes 'setShape' method
	
			// SHOULD BE RE-IMPLEMENTED BY THE RENDERER!
			return null;	// dojox/gfx/shape.Shape
		}
	};
	
	/*=====
	 lang.extend(shape.Surface, shape.Container);
	 lang.extend(shape.Surface, shape.Creator);

	 g.Group = declare(shape.Shape, {
		// summary:
		//		a group shape, which can be used
		//		to logically group shapes (e.g, to propagate matricies)
	});
	lang.extend(g.Group, shape.Container);
	lang.extend(g.Group, shape.Creator);

	g.Rect     = shape.Rect;
	g.Circle   = shape.Circle;
	g.Ellipse  = shape.Ellipse;
	g.Line     = shape.Line;
	g.Polyline = shape.Polyline;
	g.Text     = shape.Text;
	g.Surface  = shape.Surface;
	=====*/

	return shape;
});

},
'dojox/gfx/matrix':function(){
define(["./_base","dojo/_base/lang"], 
  function(g, lang){
	var m = g.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 = m.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;
					}
					lang.mixin(this, matrix);
				}
			}else{
				lang.mixin(this, arg);
			}
		}
	};

	// the default (identity) matrix, which is used to fill in missing values
	lang.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});

	lang.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|dojox/gfx.Point
			//		an x coordinate value, or a point-like object, which specifies offsets for both dimensions
			// b: Number?
			//		a y coordinate value
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 1){
				return new m.Matrix2D({dx: a, dy: b}); // dojox/gfx/matrix.Matrix2D
			}
			// branch
			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|dojox/gfx.Point
			//		a scaling factor used for the x coordinate, or
			//		a uniform scaling factor used for the both coordinates, or
			//		a point-like object, which specifies scale factors for both dimensions
			// b: Number?
			//		a scaling factor used for the y coordinate
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 1){
				return new m.Matrix2D({xx: a, yy: b}); // dojox/gfx/matrix.Matrix2D
			}
			if(typeof a == "number"){
				return new m.Matrix2D({xx: a, yy: a}); // dojox/gfx/matrix.Matrix2D
			}
			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)
			// returns: dojox/gfx/matrix.Matrix2D
			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)
			// returns: dojox/gfx/matrix.Matrix2D
			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
			//		a skewing angle in radians
			// returns: dojox/gfx/matrix.Matrix2D
			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
			//		a skewing angle in degrees
			// returns: dojox/gfx/matrix.Matrix2D
			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
			//		a skewing angle in radians
			// returns: dojox/gfx/matrix.Matrix2D
			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
			//		a skewing angle in degrees
			// returns: dojox/gfx/matrix.Matrix2D
			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|Number
			//		a point-like object, which specifies a vector of reflection, or an X value
			// b: Number?
			//		a Y value
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length == 1){
				b = a.y;
				a = a.x;
			}
			// 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|Number
			//		a point-like object, which specifies a vector of projection, or
			//		an x coordinate value
			// b: Number?
			//		a y coordinate value
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length == 1){
				b = a.y;
				a = a.x;
			}
			// 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
			// returns: dojox/gfx/matrix.Matrix2D
			return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox/gfx/matrix.Matrix2D
		},

		// common operations

		isIdentity: function(matrix){
			// summary:
			//		returns whether the specified matrix is the identity.
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a 2D matrix object to be tested
			// returns: Boolean
			return matrix.xx == 1 && matrix.xy == 0 && matrix.yx == 0 && matrix.yy == 1 && matrix.dx == 0 && matrix.dy == 0; // Boolean
		},
		clone: function(matrix){
			// summary:
			//		creates a copy of a 2D matrix
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a 2D matrix-like object to be cloned
			// returns: dojox/gfx/matrix.Matrix2D
			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
			// returns: dojox/gfx/matrix.Matrix2D
			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
			// returns: dojox/gfx.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? */ b){
			// summary:
			//		applies a matrix to a point
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a 2D matrix object to be applied
			// a: Number|dojox/gfx.Point
			//		an x coordinate of a point, or a point
			// b: Number?
			//		a y coordinate of a point
			// returns: dojox/gfx.Point
			var M = m.normalize(matrix);
			if(typeof a == "number" && typeof b == "number"){
				return m._multiplyPoint(M, a, b); // dojox/gfx.Point
			}
			return m._multiplyPoint(M, a.x, a.y); // dojox/gfx.Point
		},
		multiplyRectangle: function(matrix, /*Rectangle*/ rect){
			// summary:
			//		Applies a matrix to a rectangle.
			// description:
			//		The method applies the transformation on all corners of the
			//		rectangle and returns the smallest rectangle enclosing the 4 transformed
			//		points.
			// matrix: dojox/gfx/matrix.Matrix2D
			//		a 2D matrix object to be applied.
			// rect: Rectangle
			//		the rectangle to transform.
			// returns: dojox/gfx.Rectangle
			var M = m.normalize(matrix);
			rect = rect || {x:0, y:0, width:0, height:0}; 
			if(m.isIdentity(M))
				return {x: rect.x, y: rect.y, width: rect.width, height: rect.height}; // dojo/gfx.Rectangle
			var p0 = m.multiplyPoint(M, rect.x, rect.y),
				p1 = m.multiplyPoint(M, rect.x, rect.y + rect.height),
				p2 = m.multiplyPoint(M, rect.x + rect.width, rect.y),
				p3 = m.multiplyPoint(M, rect.x + rect.width, rect.y + rect.height),
				minx = Math.min(p0.x, p1.x, p2.x, p3.x),
				miny = Math.min(p0.y, p1.y, p2.y, p3.y),
				maxx = Math.max(p0.x, p1.x, p2.x, p3.x),
				maxy = Math.max(p0.y, p1.y, p2.y, p3.y);
			return{ // dojo/gfx.Rectangle
				x: minx,
				y: miny,
				width: maxx - minx,
				height: maxy - miny
			};
		},
		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 central 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, or a uniform scaling factor used for both coordinates
			// b: Number?
			//		a scaling factor used for the y coordinate
			// c: Number|Point
			//		an x component of a central point, or a central point
			// d: Number
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			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"){
						return m._sandwich(m.scale(a), b, c); // dojox/gfx/matrix.Matrix2D
					}
					return m._sandwich(m.scale(a, b), c.x, c.y); // dojox/gfx/matrix.Matrix2D
			}
			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|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.rotate(angle), a, b); // dojox/gfx/matrix.Matrix2D
			}
			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|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.rotateg(degree), a, b); // dojox/gfx/matrix.Matrix2D
			}
			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
			//		a skewing angle in radians
			// a: Number|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.skewX(angle), a, b); // dojox/gfx/matrix.Matrix2D
			}
			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
			//		a skewing angle in degrees
			// a: Number|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.skewXg(degree), a, b); // dojox/gfx/matrix.Matrix2D
			}
			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
			//		a skewing angle in radians
			// a: Number|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.skewY(angle), a, b); // dojox/gfx/matrix.Matrix2D
			}
			return m._sandwich(m.skewY(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
		},
		skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number? */ 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
			//		a skewing angle in degrees
			// a: Number|dojox/gfx.Point
			//		an x component of a central point, or a central point
			// b: Number?
			//		a y component of a central point
			// returns: dojox/gfx/matrix.Matrix2D
			if(arguments.length > 2){
				return m._sandwich(m.skewYg(degree), a, b); // dojox/gfx/matrix.Matrix2D
			}
			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
	g.Matrix2D = m.Matrix2D;

	return m;
});



},
'dojox/geo/openlayers/GfxLayer':function(){
define([
	"dojo/_base/declare",
	"dojo/_base/connect",
	"dojo/dom-style",
	"dojox/gfx",
	"dojox/gfx/matrix",
	"./Feature",
	"./Layer"
], function(declare, connect, style, gfx, matrix, Feature, Layer){

	return declare("dojox.geo.openlayers.GfxLayer", Layer, {
		// summary:
		//		A layer dedicated to render dojox.geo.openlayers.GeometryFeature
		// description:
		//		A layer class for rendering geometries as dojox.gfx.Shape objects.
		//		This layer class accepts Features which encapsulates graphic objects to be added to the map.
		//		All objects should be added to this group.
		// tags:
		//		private
		_viewport: null,

		constructor: function(name, options){
			// summary:
			//		Constructs a new GFX layer.
			var s = gfx.createSurface(this.olLayer.div, 100, 100);
			this._surface = s;
			var vp;
			if(options && options.viewport){
				vp = options.viewport;
			}else{
				vp = s.createGroup();
			}
			this.setViewport(vp);
			connect.connect(this.olLayer, "onMapResize", this, "onMapResize");
			this.olLayer.getDataExtent = this.getDataExtent;
		},

		getViewport: function(){
			// summary:
			//		Gets the viewport
			// tags:
			//		internal
			return this._viewport;
		},

		setViewport: function(g){
			// summary:
			//		Sets the viewport
			// g: dojox.gfx.Group
			// tags:
			//		internal
			if(this._viewport){
				this._viewport.removeShape();
			}
			this._viewport = g;
			this._surface.add(g);
		},

		onMapResize: function(){
			// summary:
			//		Called when map is resized.
			// tags:
			//		protected
			this._surfaceSize();
		},

		setMap: function(map){
			// summary:
			//		Sets the map for this layer.
			// tags:
			//		protected
			this.inherited(arguments);
			this._surfaceSize();
		},

		getDataExtent: function(){
			// summary:
			//		Get data extent
			// tags:
			//		private
			var ret = this._surface.getDimensions();
			return ret;
		},

		getSurface: function(){
			// summary:
			//		Get the underlying dojox.gfx.Surface
			// returns:
			//		The dojox.gfx.Surface this layer uses to draw its GFX rendering.
			return this._surface; // dojox.gfx.Surface
		},

		_surfaceSize: function(){
			// summary:
			//		Recomputes the surface size when being resized.
			// tags:
			//		private
			var s = this.olLayer.map.getSize();
			this._surface.setDimensions(s.w, s.h);
		},

		moveTo: function(event){
			// summary:
			//		Called when this layer is moved or zoomed.
			// event:
			//		The event
			var s = style.get(this.olLayer.map.layerContainerDiv);
			var left = parseInt(s.left);
			var top = parseInt(s.top);

			if(event.zoomChanged || left || top){
				var d = this.olLayer.div;

				style.set(d, {
					left: -left + "px",
					top: -top + "px"
				});

				if(this._features == null){
					return;
				}
				var vp = this.getViewport();

				vp.setTransform(matrix.translate(left, top));

				this.inherited(arguments);

			}
		},

		added: function(){
			// summary:
			//		Called when added to a map.
			this.inherited(arguments);
			this._surfaceSize();
		}

	});
});

},
'dojox/geo/openlayers/Collection':function(){
define([
	"dojo/_base/declare",
	"./Geometry"
], function(declare, Geometry){

	return declare("dojox.geo.openlayers.Collection", Geometry, {
		// summary:
		//		A collection of geometries. 

		// coordinates: Array
		//		An array of geometries.
		coordinates:null,

		setGeometries: function(g){
			// summary:
			//		Sets the geometries
			// g: Array
			//		The array of geometries.
			this.coordinates = g;
		},

		getGeometries: function(){
			// summary:
			//		Returns the geometries.
			// returns:
			//		The array of geometries defining this collection.
			return this.coordinates; // Array
		}
	});
});

},
'dojox/geo/openlayers/Geometry':function(){
define([
	"dojo/_base/declare"
], function(declare){

	return declare("dojox.geo.openlayers.Geometry", null, {
		// summary:
		//		A Geometry handles description of shapes to be rendered in a GfxLayer
		//		using a GeometryFeature feature.
		//		A Geometry can be:
		//
		//		- A point geometry of type dojox.geo.openlayers.Point. Coordinates are a an 
		//		Object {x, y}
		//		- A line string geometry of type dojox.geo.openlayers.LineString. Coordinates are
		//		an array of {x, y} objects
		//		- A collection geometry of type dojox.geo.openlayers.Collection. Coordinates are an array of geometries.

		// coordinates: Object|Array
		//		The coordinates of the geometry, Object like {x, y} or Array.
		coordinates : null,

		// shape: [private] dojox/gfx/shape.Shape
		//		The associated shape when rendered
		shape: null,

		constructor: function(coords){
			// summary:
			//		Constructs a new geometry
			// coords: Object
			//		Coordinates of the geometry. {x:``x``, y:``y``} object for a point geometry, array of {x:``x``, y:``y``}
			//		objects for line string geometry, array of geometries for collection geometry.
			this.coordinates = coords;
		}
	});
});

},
'dojox/geo/openlayers/GeometryFeature':function(){
define([
	"dojo/_base/declare",
	"dojo/_base/array",
	"dojo/_base/lang",
	"dojox/gfx/matrix",
	"./Point",
	"./LineString",
	"./Collection",
	"./Feature"
], function(declare, array, lang, matrix, Point, LineString, Collection, Feature){

	return declare("dojox.geo.openlayers.GeometryFeature", Feature, {
		// summary:
		//		A Feature encapsulating a geometry.
		// description:
		//		This Feature renders a geometry such as a Point or LineString geometry. This Feature
		//		is responsible for reprojecting the geometry before creating a gfx shape to display it.
		//		By default the shape created is a circle for a Point geometry and a polyline for a 
		//		LineString geometry. User can change these behavior by overriding the createShape 
		//		method to create the desired shape.
		// example:
		//	|  var geom = new dojox.geo.openlayers.Point({x:0, y:0});
		//	|  var gf = new dojox.geo.openlayers.GeometryFeature(geom);

		constructor: function(geometry){
			// summary:
			//		Constructs a GeometryFeature for the specified geometry.
			// geometry: dojox/geo/openlayers/Geometry
			//		The geometry to render.
			this._geometry = geometry;
			this._shapeProperties = {};
			this._fill = null;
			this._stroke = null;
		},

		_createCollection: function(/* dojox/geo/openlayers/Geometry */g){
			// summary:
			//		Create collection shape and add it to the viewport.
			// tags:
			//		private
			var layer = this.getLayer();
			var s = layer.getSurface();
			var c = this.createShape(s, g);
			var vp = layer.getViewport();
			vp.add(c);
			return c;
		},

		_getCollectionShape: function(/* dojox/geo/openlayers/Geometry */g){
			// summary:
			//		Get the collection shape, create it if necessary
			// tags:
			//		private
			var s = g.shape;
			if(s == null){
				s = this._createCollection(g);
				g.shape = s;
			}
			return s;
		},

		renderCollection: function(g){
			// summary:
			//		Renders a geometry collection.
			// g: dojox.geo.openlayers.Geometry?
			//		The geometry to render.
			if(g == undefined){
				g = this._geometry;
			}

			s = this._getCollectionShape(g);
			var prop = this.getShapeProperties();
			s.setShape(prop);

			array.forEach(g.coordinates, function(item){
				if(item instanceof Point){
					this.renderPoint(item);
				}else if(item instanceof LineString){
					this.renderLineString(item);
				}else if(item instanceof Collection){
					this.renderCollection(item);
				}else{
					throw new Error();
				}
			}, this);
			this._applyStyle(g);
		},

		render: function(g){
			// summary:
			//		Render a geometry. 
			//		Called by the Layer on which the feature is added. 
			// g: dojox/geo/openlayer/Geometry?
			//		The geometry to draw
			if(g == undefined){
				g = this._geometry;
			}

			if(g instanceof Point){
				this.renderPoint(g);
			}else if(g instanceof LineString){
				this.renderLineString(g);
			}else if(g instanceof Collection){
				this.renderCollection(g);
			}else{
				throw new Error();
			}
		},

		getShapeProperties: function(){
			// summary:
			//		Returns the shape properties. 
			// returns: Object
			//		The shape properties.
			return this._shapeProperties;
		},

		setShapeProperties: function(s){
			// summary:
			//		Sets the shape properties. 
			// s: Object
			//		The shape properties to set.
			this._shapeProperties = s;
			return this;
		},

		createShape: function(s, g){
			// summary:
			//		Called when the shape rendering the geometry has to be created.
			//		This default implementation creates a circle for a point geometry, a polyline for
			//		a LineString geometry and is recursively called when creating a collection.
			//		User may replace this method to produce a custom shape.
			// s: dojox/gfx/Surface
			//		The surface on which the method create the shapes.
			// g: dojox/geo/openlayers/Geometry?
			//		The reference geometry 
			// returns:
			//		The resulting shape.
			if(!g){
				g = this._geometry;
			}

			var shape = null;
			if(g instanceof Point){
				shape = s.createCircle();
			}else if(g instanceof LineString){
				shape = s.createPolyline();
			}else if(g instanceof Collection){
				var grp = s.createGroup();
				array.forEach(g.coordinates, function(item){
					var shp = this.createShape(s, item);
					grp.add(shp);
				}, this);
				shape = grp;
			}else{
				throw new Error();
			}
			return shape;
		},

		getShape: function(){
			// summary:
			//		Returns the shape rendering the geometry
			// returns:
			//		The shape used to render the geometry.
			var g = this._geometry;
			if(!g){
				return null;
			}
			if(g.shape){
				return g.shape;
			}
			this.render();
			return g.shape; // dojox.gfx.shape.Shape
		},

		_createPoint: function(/* dojox/geo/openlayer/Geometry */g){
			// summary:
			//		Create a point shape
			// tags:
			//		private
			var layer = this.getLayer();
			var s = layer.getSurface();
			var c = this.createShape(s, g);
			var vp = layer.getViewport();
			vp.add(c);
			return c;
		},

		_getPointShape: function(/* dojox/geo/openlayers/Geometry */g){
			// summary:
			//		get the point geometry shape, create it if necessary
			// tags:
			//		private
			var s = g.shape;
			if(s == null){
				s = this._createPoint(g);
				g.shape = s;
			}
			return s;
		},

		renderPoint: function(g){
			// summary:
			//		Renders a point geometry.
			// g: dojox/geo/openlayers/Point?
			//		The geometry to render, or the current instance geometry if not specified.
			if(g == undefined){
				g = this._geometry;
			}
			var layer = this.getLayer();
			var map = layer.getDojoMap();

			s = this._getPointShape(g);
			var prop = lang.mixin({}, this._defaults.pointShape);
			prop = lang.mixin(prop, this.getShapeProperties());
			s.setShape(prop);

			var from = this.getCoordinateSystem();
			var p = map.transform(g.coordinates, from);

			var a = this._getLocalXY(p);
			var cx = a[0];
			var cy = a[1];
			var tr = layer.getViewport().getTransform();
			if(tr){
				s.setTransform(matrix.translate(cx - tr.dx, cy - tr.dy));
			}
			this._applyStyle(g);
		},

		_createLineString: function(/* dojox/geo/openlayers/Geometry */g){
			// summary:
			//		Create polyline shape and add it to the viewport.
			// tags:
			//		private
			var layer = this.getLayer();
			var s = layer._surface;
			var shape = this.createShape(s, g);
			var vp = layer.getViewport();
			vp.add(shape);
			g.shape = shape;
			return shape;
		},

		_getLineStringShape: function(/* dojox/geo/openlayers/Geometry */g){
			// summary:
			//		Get the line string geometry shape, create it if necessary
			// tags:
			//		private
			var s = g.shape;
			if(s == null){
				s = this._createLineString(g);
				g.shape = s;
			}
			return s;
		},

		renderLineString: function(g){
			// summary:
			//		Renders a line string geometry.
			// g: dojox/geo/openlayers/Geometry?
			//		The geometry to render.
			if(g == undefined){
				g = this._geometry;
			}
			var layer = this.getLayer();
			var map = layer.getDojoMap();
			var lss = this._getLineStringShape(g);
			var from = this.getCoordinateSystem();
			var points = new Array(g.coordinates.length); // ss.getShape().points;		
			var tr = layer.getViewport().getTransform();
			array.forEach(g.coordinates, function(c, i, array){
				var p = map.transform(c, from);
				var a = this._getLocalXY(p);
				if(tr){
					a[0] -= tr.dx;
					a[1] -= tr.dy;
				}
				points[i] = {
					x: a[0],
					y: a[1]
				};
			}, this);
			var prop = lang.mixin({}, this._defaults.lineStringShape);
			prop = lang.mixin(prop, this.getShapeProperties());
			prop = lang.mixin(prop, {
				points: points
			});
			lss.setShape(prop);
			this._applyStyle(g);
		},

		_applyStyle: function(g){
			// summary:
			//		Apply the style on the geometry's shape.
			// g: Geometry
			//		The geometry.
			// tags:
			//		private
			if(!g || !g.shape){
				return;
			}

			var f = this.getFill();

			var fill;
			if(!f || lang.isString(f) || lang.isArray(f)){
				fill = f;
			}else{
				fill = lang.mixin({}, this._defaults.fill);
				fill = lang.mixin(fill, f);
			}

			var s = this.getStroke();
			var stroke;
			if(!s || lang.isString(s) || lang.isArray(s)){
				stroke = s;
			}else{
				stroke = lang.mixin({}, this._defaults.stroke);
				stroke = lang.mixin(stroke, s);
			}

			this._applyRecusiveStyle(g, stroke, fill);
		},

		_applyRecusiveStyle: function(g, stroke, fill){
			// summary:
			//		Apply the style on the geometry's shape recursively.
			// g: dojox.geo.openlayers.Geometry
			//		The geometry.
			// stroke: Object
			//		The stroke
			// fill:Object
			//		The fill
			// tags:
			//		private
			var shp = g.shape;

			if(shp.setFill){
				shp.setFill(fill);
			}

			if(shp.setStroke){
				shp.setStroke(stroke);
			}

			if(g instanceof Collection){
				array.forEach(g.coordinates, function(i){
					this._applyRecusiveStyle(i, stroke, fill);
				}, this);
			}
		},

		setStroke: function(s){
			// summary:
			//		Set the stroke style to be applied on the rendered shape.
			// s: Object
			//		The stroke style
			this._stroke = s;
			return this;
		},

		getStroke: function(){
			// summary:
			//		Returns the stroke style
			// returns:
			//		The stroke style
			return this._stroke;
		},

		setFill: function(f){
			// summary:
			//		Set the fill style to be applied on the rendered shape.
			// f: Object
			//		The fill style
			this._fill = f;
			return this;
		},

		getFill: function(){
			// summary:
			//		Returns the fill style
			// returns:
			//		The fill style
			return this._fill;
		},

		remove: function(){
			// summary:
			//		Removes the shape from the Surface. 
			//		Called when the feature is removed from the layer.
			var g = this._geometry;
			var shp = g.shape;
			g.shape = null;
			if(shp){
				shp.removeShape();
			}
			if(g instanceof Collection){
				array.forEach(g.coordinates, function(i){
					this.remove(i);
				}, this);
			}
		},

		_defaults: {
			fill: null,
			stroke: null,
			pointShape: {
				r: 30
			},
			lineStringShape: null
		}

	});
});

},
'dojox/geo/openlayers/Point':function(){
define([
	"dojo/_base/declare",
	"./Geometry"
], function(declare, Geometry){

	return declare("dojox.geo.openlayers.Point", Geometry, {
		// summary:
		//		A Point geometry handles description of points to be rendered in a GfxLayer

		setPoint: function(p){
			// summary:
			//		Sets the point for this geometry.
			// p: Object
			//		The point geometry expressed as a {x, y} object.
			this.coordinates = p;
		},

		getPoint: function(){
			// summary:
			//		Gets the point defining this geometry.
			// returns:
			//		The point defining this geometry.
			return this.coordinates; // Object
		}
	});
});

},
'dojox/geo/openlayers/LineString':function(){
define([
	"dojo/_base/declare",
	"./Geometry"
], function(declare, Geometry){

	return declare("dojox.geo.openlayers.LineString", Geometry, {
		// summary:
		//		The `dojox.geo.openlayers.LineString` geometry. This geometry holds an array
		//		of coordinates.

		setPoints: function(p){
			// summary:
			//		Sets the points for this geometry.
			// p: Object[]
			//		An array of {x, y} objects
			this.coordinates = p;
		},

		getPoints: function(){
			// summary:
			//		Gets the points of this geometry.
			// returns:
			//		The points of this geometry.
			return this.coordinates; // Object[]
		}

	});
});

},
'dojox/geo/openlayers/JsonImport':function(){
define([
	"dojo/_base/declare",
	"dojo/_base/xhr",
	"dojo/_base/lang",
	"dojo/_base/array",
	"./LineString",
	"./Collection",
	"./GeometryFeature"
], function(declare, xhr, lang, array, LineString, Collection, GeometryFeature){

	/*=====
	dojox.geo.openlayers.__JsonImportArgs = {
		// summary:
		//		The keyword arguments that can be passed in a JsonImport constructor.
		// url: String
		//		The url pointing to the JSON file to load.
		// nextFeature: function
		//		The function called each time a feature is read. The function is called with a GeometryFeature as argument.
		// error: function
		//		Error callback called if something fails.
	};
	=====*/

	return declare("dojox.geo.openlayers.JsonImport", null, {
		// summary:
		//		Class to load JSON formated ShapeFile as output of the JSon Custom Map Converter.
		// description:
		//		This class loads JSON formated ShapeFile produced by the JSon Custom Map Converter.
		//		When loading the JSON file, it calls a iterator function each time a feature is read.
		//		This iterator function is provided as parameter to the constructor.
		//
		constructor : function(params){
			// summary:
			//		Construct a new JSON importer.
			// params: dojox.geo.openlayers.__JsonImportArgs
			//		The parameters to initialize this JsonImport instance.
			this._params = params;
		},

		loadData: function(){
			// summary:
			//		Triggers the loading.
			var p = this._params;
			xhr.get({
				url: p.url,
				handleAs: "json",
				sync: true,
				load: lang.hitch(this, this._gotData),
				error: lang.hitch(this, this._loadError)
			});
		},

		_gotData: function(/* Object */items){
			// summary:
			//		Called when loading is complete.
			// tags:
			//		private
			var nf = this._params.nextFeature;
			if(!lang.isFunction(nf)){
				return;
			}

			var extent = items.layerExtent;
			var ulx = extent[0];
			var uly = extent[1];
			var lrx = ulx + extent[2];
			var lry = uly + extent[3];

			var extentLL = items.layerExtentLL;
			var x1 = extentLL[0];
			var y1 = extentLL[1];
			var x2 = x1 + extentLL[2];
			var y2 = y1 + extentLL[3];

			var ulxLL = x1;
			var ulyLL = y2;
			var lrxLL = x2;
			var lryLL = y1;

			var features = items.features;

			for( var f in features){
				var o = features[f];
				var s = o["shape"];
				var gf = null;
				if(lang.isArray(s[0])){

					var a = new Array();
					array.forEach(s, function(item){
						var ls = this._makeGeometry(item, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
						a.push(ls);
					}, this);
					var g = new Collection(a);
					gf = new GeometryFeature(g);
					nf.call(this, gf);

				}else{
					gf = this._makeFeature(s, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
					nf.call(this, gf);
				}
			}
			var complete = this._params.complete;
			if(lang.isFunction(complete)){
				complete.call(this, complete);
			}
		},

		_makeGeometry: function(/* Array */s, /* Float */ulx, /* Float */uly, /* Float */lrx, /* Float */
		lry, /* Float */ulxLL, /* Float */ulyLL, /* Float */lrxLL, /* Float */lryLL){
			// summary:
			//		Make a geometry with the specified points.
			// tags:
			//		private
			var a = [];
			var k = 0.0;
			for( var i = 0; i < s.length - 1; i += 2){
				var x = s[i];
				var y = s[i + 1];

				k = (x - ulx) / (lrx - ulx);
				var px = k * (lrxLL - ulxLL) + ulxLL;

				k = (y - uly) / (lry - uly);
				var py = k * (lryLL - ulyLL) + ulyLL;

				a.push({
					x: px,
					y: py
				});

			}
			var ls = new LineString(a);
			return ls; // LineString
		},

		_makeFeature: function(/* Array */s, /* Float */ulx, /* Float */uly, /* Float */lrx, /* Float */
		lry, /* Float */ulxLL, /* Float */ulyLL, /* Float */lrxLL, /* Float */lryLL){
			// summary:
			//		Make a GeometryFeature with the specified points.
			// tags:
			//		private
			var ls = this._makeGeometry(s, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
			var gf = new GeometryFeature(ls);
			return gf;
		},

		_loadError: function(){
			// summary:
			//		Called when an error occurs. Calls the error function is provided in the parameters.
			// tags:
			//		private
			var f = this._params.error;
			if(lang.isFunction(f)){
				f.apply(this, parameters);
			}
		}
	});
});

},
'dojox/geo/openlayers/WidgetFeature':function(){
define([
	"dojo/_base/declare",
	"dojo/dom-style",
	"dojo/_base/lang",
	"dijit/registry",
	"./Feature"
], function(declare, style, lang, registry, Feature){
	/*=====
	dojox.geo.openlayers.__WidgetFeatureArgs = {
		// summary:
		//		The keyword arguments that can be passed in a WidgetFeature constructor.
		//		You must define a least one widget retrieval parameter and the geo-localization parameters.
		// createWidget: Function?
		//		Function for widget creation. Must return a `dijit._Widget.
		// dojoType: String?
		//		The class of a widget to create.
		// dijitId: String?
		//		The digitId of an existing widget.
		// widget: dijit._Widget?
		//		An already created widget.
		// width: Number?
		//		The width of the widget.
		// height: Number?
		//		The height of the widget.
		// longitude: Number
		//		The longitude, in decimal degrees where to place the widget.
		// latitude: Number
		//		The latitude, in decimal degrees where to place the widget.
	};
	=====*/

		return declare("dojox.geo.openlayers.WidgetFeature", Feature, {
			// summary:
			//		Wraps a Dojo widget, provide geolocalisation of the widget and interface
			//		to Layer class.
			// description:
			//		This class allows to add a widget in a `dojox.geo.openlayers.Layer`.

			_widget: null,
			_bbox: null,

			constructor: function(params){
				// summary:
				//		Constructs a new `dojox.geo.openlayers.WidgetFeature`
				// params: dojox.geo.openlayers.__WidgetFeatureArgs
				//		The parameters describing the widget.
				this._params = params;
			},

			setParameters: function(params){
				// summary:
				//		Sets the parameters describing the widget.
				// params: dojox.geo.openlayers.__WidgetFeatureArgs
				//		The parameters describing the widget.
				this._params = params;
			},

			getParameters: function(){
				// summary:
				//		Returns the parameters describing the widget.
				// returns: dojox.geo.openlayers.__WidgetFeatureArgs
				//		The parameters describing the widget.
				return this._params;
			},

			_getWidget: function(){
				// summary:
				//		Creates, if necessary the widget and returns it
				// tags:
				//		private
				var params = this._params;

				if((this._widget == null) && (params != null)){
					var w = null;

					if(typeof (params.createWidget) == "function"){
						w = params.createWidget.call(this);
					}else if(params.dojoType){
						dojo["require"](params.dojoType);
						var c = lang.getObject(params.dojoType);
						w = new c(params);
					}else if(params.dijitId){
						w = registry.byId(params.dijitId);
					}else if(params.widget){
						w = params.widget;
					}

					if(w != null){
						this._widget = w;
						if(typeof (w.startup) == "function"){
							w.startup();
						}
						var n = w.domNode;
						if(n != null){
							style.set(n, {
								position: "absolute"
							});
						}
					}
					this._widget = w;
				}
				return this._widget;
			},

			_getWidgetWidth: function(){
				// summary:
				//		gets the widget width
				// tags:
				//		private
				var p = this._params;
				if(p.width){
					return p.width;
				}
				var w = this._getWidget();
				if(w){
					return style.get(w.domNode, "width");
				}
				return 10;
			},

			_getWidgetHeight: function(){
				// summary:
				//		gets the widget height
				// tags:
				//		private
				var p = this._params;
				if(p.height){
					return p.height;
				}
				var w = this._getWidget();
				if(w){
					return style.get(w.domNode, "height");
				}
				return 10;
			},

			render: function(){
				// summary:
				//		renders the widget.
				// description:
				//		Places the widget accordingly to longitude and latitude defined in parameters.
				//		This function is called when the center of the maps or zoom factor changes.
				var layer = this.getLayer();

				var widget = this._getWidget();
				if(widget == null){
					return;
				}
				var params = this._params;
				var lon = params.longitude;
				var lat = params.latitude;
				var from = this.getCoordinateSystem();
				var map = layer.getDojoMap();
				var p = map.transformXY(lon, lat, from);
				var a = this._getLocalXY(p);

				var width = this._getWidgetWidth();
				var height = this._getWidgetHeight();

				var x = a[0] - width / 2;
				var y = a[1] - height / 2;
				var dom = widget.domNode;

				var pa = layer.olLayer.div;
				if(dom.parentNode != pa){
					if(dom.parentNode){
						dom.parentNode.removeChild(dom);
					}
					pa.appendChild(dom);
				}
				this._updateWidgetPosition({
					x: x,
					y: y,
					width: width,
					height: height
				});
			},

			_updateWidgetPosition: function(box){
				// summary:
				//		Places the widget with the computed x and y values
				// tags:
				//		private
				
				// var box = this._params;

				var w = this._widget;
				var dom = w.domNode;

				style.set(dom, {
					position: "absolute",
					left: box.x + "px",
					top: box.y + "px",
					width: box.width + "px",
					height: box.height + "px"
				});

				if(w.srcNodeRef){
					style.set(w.srcNodeRef, {
						position: "absolute",
						left: box.x + "px",
						top: box.y + "px",
						width: box.width + "px",
						height: box.height + "px"
					});
				}

				if(lang.isFunction(w.resize)){
					w.resize({
						w: box.width,
						h: box.height
					});
				}
			},

			remove: function(){
				// summary:
				//		removes this feature.
				// description:
				//		Remove this feature by disconnecting the widget from the dom.
				var w = this._getWidget();
				if(!w){
					return;
				}
				var dom = w.domNode;
				if(dom.parentNode){
					dom.parentNode.removeChild(dom);
				}
			}
		});
	});

},
'dojox/gfx/svg':function(){
define(["dojo/_base/lang", "dojo/_base/sniff", "dojo/_base/window", "dojo/dom", "dojo/_base/declare", "dojo/_base/array",
  "dojo/dom-geometry", "dojo/dom-attr", "dojo/_base/Color", "./_base", "./shape", "./path"],
function(lang, has, win, dom, declare, arr, domGeom, domAttr, Color, g, gs, pathLib){

	var svg = g.svg = {
		// summary:
		//		This the graphics rendering bridge for browsers compliant with W3C SVG1.0.
		//		This is the preferred renderer to use for interactive and accessible graphics.
	};
	svg.useSvgWeb = (typeof window.svgweb != "undefined");

	// Need to detect iOS in order to workaround bug when
	// touching nodes with text
	var uagent = navigator.userAgent,
		safMobile = has("ios"),
		android = has("android"),
		textRenderingFix = has("chrome") || (android && android>=4) ? "auto" : "optimizeLegibility";// #16099, #16461

	function _createElementNS(ns, nodeType){
		// summary:
		//		Internal helper to deal with creating elements that
		//		are namespaced.  Mainly to get SVG markup output
		//		working on IE.
		if(win.doc.createElementNS){
			return win.doc.createElementNS(ns,nodeType);
		}else{
			return win.doc.createElement(nodeType);
		}
	}
	
	function _setAttributeNS(node, ns, attr, value){
		if(node.setAttributeNS){
			return node.setAttributeNS(ns, attr, value);
		}else{
			return node.setAttribute(attr, value);
		}
	}

	function _createTextNode(text){
		if(svg.useSvgWeb){
			return win.doc.createTextNode(text, true);
		}else{
			return win.doc.createTextNode(text);
		}
	}

	function _createFragment(){
		if(svg.useSvgWeb){
			return win.doc.createDocumentFragment(true);
		}else{
			return win.doc.createDocumentFragment();
		}
	}

	svg.xmlns = {
		xlink: "http://www.w3.org/1999/xlink",
		svg:   "http://www.w3.org/2000/svg"
	};

	svg.getRef = function(name){
		// summary:
		//		looks up a node by its external name
		// name: String
		//		an SVG external reference
		// returns:
		//      returns a DOM Node specified by the name argument or null
		if(!name || name == "none") return null;
		if(name.match(/^url\(#.+\)$/)){
			return dom.byId(name.slice(5, -1));	// Node
		}
		// alternative representation of a reference
		if(name.match(/^#dojoUnique\d+$/)){
			// we assume here that a reference was generated by dojox/gfx
			return dom.byId(name.slice(1));	// Node
		}
		return null;	// Node
	};

	svg.dasharray = {
		solid:				"none",
		shortdash:			[4, 1],
		shortdot:			[1, 1],
		shortdashdot:		[4, 1, 1, 1],
		shortdashdotdot:	[4, 1, 1, 1, 1, 1],
		dot:				[1, 3],
		dash:				[4, 3],
		longdash:			[8, 3],
		dashdot:			[4, 3, 1, 3],
		longdashdot:		[8, 3, 1, 3],
		longdashdotdot:		[8, 3, 1, 3, 1, 3]
	};

	var clipCount = 0;

	svg.Shape = declare("dojox.gfx.svg.Shape", gs.Shape, {
		// summary:
		//		SVG-specific implementation of dojox/gfx/shape.Shape methods

		destroy: function(){
			if(this.fillStyle && "type" in this.fillStyle){
				var fill = this.rawNode.getAttribute("fill"),
					ref  = svg.getRef(fill);
				if(ref){
					ref.parentNode.removeChild(ref);
				}
			}
			if(this.clip){
				var clipPathProp = this.rawNode.getAttribute("clip-path");
				if(clipPathProp){
					var clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
					if(clipNode){ clipNode.parentNode.removeChild(clipNode); }
				}
			}
			gs.Shape.prototype.destroy.apply(this, arguments);
		},

		setFill: function(fill){
			// summary:
			//		sets a fill object (SVG)
			// fill: Object
			//		a fill object
			//		(see dojox/gfx.defaultLinearGradient,
			//		dojox/gfx.defaultRadialGradient,
			//		dojox/gfx.defaultPattern,
			//		or dojo/_base/Color)

			if(!fill){
				// don't fill
				this.fillStyle = null;
				this.rawNode.setAttribute("fill", "none");
				this.rawNode.setAttribute("fill-opacity", 0);
				return this;
			}
			var f;
			// FIXME: slightly magical. We're using the outer scope's "f", but setting it later
			var setter = function(x){
					// we assume that we're executing in the scope of the node to mutate
					this.setAttribute(x, f[x].toFixed(8));
				};
			if(typeof(fill) == "object" && "type" in fill){
				// gradient
				switch(fill.type){
					case "linear":
						f = g.makeParameters(g.defaultLinearGradient, fill);
						var gradient = this._setFillObject(f, "linearGradient");
						arr.forEach(["x1", "y1", "x2", "y2"], setter, gradient);
						break;
					case "radial":
						f = g.makeParameters(g.defaultRadialGradient, fill);
						var grad = this._setFillObject(f, "radialGradient");
						arr.forEach(["cx", "cy", "r"], setter, grad);
						break;
					case "pattern":
						f = g.makeParameters(g.defaultPattern, fill);
						var pattern = this._setFillObject(f, "pattern");
						arr.forEach(["x", "y", "width", "height"], setter, pattern);
						break;
				}
				this.fillStyle = f;
				return this;
			}
			// color object
			f = g.normalizeColor(fill);
			this.fillStyle = f;
			this.rawNode.setAttribute("fill", f.toCss());
			this.rawNode.setAttribute("fill-opacity", f.a);
			this.rawNode.setAttribute("fill-rule", "evenodd");
			return this;	// self
		},

		setStroke: function(stroke){
			// summary:
			//		sets a stroke object (SVG)
			// stroke: Object
			//		a stroke object (see dojox/gfx.defaultStroke)

			var rn = this.rawNode;
			if(!stroke){
				// don't stroke
				this.strokeStyle = null;
				rn.setAttribute("stroke", "none");
				rn.setAttribute("stroke-opacity", 0);
				return this;
			}
			// normalize the stroke
			if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
				stroke = { color: stroke };
			}
			var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
			s.color = g.normalizeColor(s.color);
			// generate attributes
			if(s){
				var w = s.width < 0 ? 0 : s.width;
				rn.setAttribute("stroke", s.color.toCss());
				rn.setAttribute("stroke-opacity", s.color.a);
				rn.setAttribute("stroke-width",   w);
				rn.setAttribute("stroke-linecap", s.cap);
				if(typeof s.join == "number"){
					rn.setAttribute("stroke-linejoin",   "miter");
					rn.setAttribute("stroke-miterlimit", s.join);
				}else{
					rn.setAttribute("stroke-linejoin",   s.join);
				}
				var da = s.style.toLowerCase();
				if(da in svg.dasharray){
					da = svg.dasharray[da];
				}
				if(da instanceof Array){
					da = lang._toArray(da);
					var i;
					for(i = 0; i < da.length; ++i){
						da[i] *= w;
					}
					if(s.cap != "butt"){
						for(i = 0; i < da.length; i += 2){
							da[i] -= w;
							if(da[i] < 1){ da[i] = 1; }
						}
						for(i = 1; i < da.length; i += 2){
							da[i] += w;
						}
					}
					da = da.join(",");
				}
				rn.setAttribute("stroke-dasharray", da);
				rn.setAttribute("dojoGfxStrokeStyle", s.style);
			}
			return this;	// self
		},

		_getParentSurface: function(){
			var surface = this.parent;
			for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
			return surface;
		},

		_setFillObject: function(f, nodeType){
			var svgns = svg.xmlns.svg;
			this.fillStyle = f;
			var surface = this._getParentSurface(),
				defs = surface.defNode,
				fill = this.rawNode.getAttribute("fill"),
				ref  = svg.getRef(fill);
			if(ref){
				fill = ref;
				if(fill.tagName.toLowerCase() != nodeType.toLowerCase()){
					var id = fill.id;
					fill.parentNode.removeChild(fill);
					fill = _createElementNS(svgns, nodeType);
					fill.setAttribute("id", id);
					defs.appendChild(fill);
				}else{
					while(fill.childNodes.length){
						fill.removeChild(fill.lastChild);
					}
				}
			}else{
				fill = _createElementNS(svgns, nodeType);
				fill.setAttribute("id", g._base._getUniqueId());
				defs.appendChild(fill);
			}
			if(nodeType == "pattern"){
				fill.setAttribute("patternUnits", "userSpaceOnUse");
				var img = _createElementNS(svgns, "image");
				img.setAttribute("x", 0);
				img.setAttribute("y", 0);
				img.setAttribute("width",  (f.width < 0 ? 0 : f.width).toFixed(8));
				img.setAttribute("height", (f.height < 0 ? 0 : f.height).toFixed(8));
				_setAttributeNS(img, svg.xmlns.xlink, "xlink:href", f.src);
				fill.appendChild(img);
			}else{
				fill.setAttribute("gradientUnits", "userSpaceOnUse");
				for(var i = 0; i < f.colors.length; ++i){
					var c = f.colors[i], t = _createElementNS(svgns, "stop"),
						cc = c.color = g.normalizeColor(c.color);
					t.setAttribute("offset",       c.offset.toFixed(8));
					t.setAttribute("stop-color",   cc.toCss());
					t.setAttribute("stop-opacity", cc.a);
					fill.appendChild(t);
				}
			}
			this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id") +")");
			this.rawNode.removeAttribute("fill-opacity");
			this.rawNode.setAttribute("fill-rule", "evenodd");
			return fill;
		},

		_applyTransform: function() {
			var matrix = this.matrix;
			if(matrix){
				var tm = this.matrix;
				this.rawNode.setAttribute("transform", "matrix(" +
					tm.xx.toFixed(8) + "," + tm.yx.toFixed(8) + "," +
					tm.xy.toFixed(8) + "," + tm.yy.toFixed(8) + "," +
					tm.dx.toFixed(8) + "," + tm.dy.toFixed(8) + ")");
			}else{
				this.rawNode.removeAttribute("transform");
			}
			return this;
		},

		setRawNode: function(rawNode){
			// summary:
			//		assigns and clears the underlying node that will represent this
			//		shape. Once set, transforms, gradients, etc, can be applied.
			//		(no fill & stroke by default)
			var r = this.rawNode = rawNode;
			if(this.shape.type!="image"){
				r.setAttribute("fill", "none");
			}
			r.setAttribute("fill-opacity", 0);
			r.setAttribute("stroke", "none");
			r.setAttribute("stroke-opacity", 0);
			r.setAttribute("stroke-width", 1);
			r.setAttribute("stroke-linecap", "butt");
			r.setAttribute("stroke-linejoin", "miter");
			r.setAttribute("stroke-miterlimit", 4);
			// Bind GFX object with SVG node for ease of retrieval - that is to
			// save code/performance to keep this association elsewhere
			r.__gfxObject__ = this;
		},

		setShape: function(newShape){
			// summary:
			//		sets a shape object (SVG)
			// newShape: Object
			//		a shape object
			//		(see dojox/gfx.defaultPath,
			//		dojox/gfx.defaultPolyline,
			//		dojox/gfx.defaultRect,
			//		dojox/gfx.defaultEllipse,
			//		dojox/gfx.defaultCircle,
			//		dojox/gfx.defaultLine,
			//		or dojox/gfx.defaultImage)
			this.shape = g.makeParameters(this.shape, newShape);
			for(var i in this.shape){
				if(i != "type"){
					var v = this.shape[i];
					if(i === "width" || i === "height"){
						v = v < 0 ? 0 : v;
					}
					this.rawNode.setAttribute(i, v);
				}
			}
			this.bbox = null;
			return this;	// self
		},

		// move family

		_moveToFront: function(){
			// summary:
			//		moves a shape to front of its parent's list of shapes (SVG)
			this.rawNode.parentNode.appendChild(this.rawNode);
			return this;	// self
		},
		_moveToBack: function(){
			// summary:
			//		moves a shape to back of its parent's list of shapes (SVG)
			this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild);
			return this;	// self
		},
		setClip: function(clip){
			// summary:
			//		sets the clipping area of this shape.
			// description:
			//		This method overrides the dojox/gfx/shape.Shape.setClip() method.
			// clip: Object
			//		an object that defines the clipping geometry, or null to remove clip.
			this.inherited(arguments);
			var clipType = clip ? "width" in clip ? "rect" : 
							"cx" in clip ? "ellipse" : 
							"points" in clip ? "polyline" : "d" in clip ? "path" : null : null;
			if(clip && !clipType){
				return this;
			}
			if(clipType === "polyline"){
				clip = lang.clone(clip);
				clip.points = clip.points.join(",");
			}
			var clipNode, clipShape,
				clipPathProp = domAttr.get(this.rawNode, "clip-path");
			if(clipPathProp){
				clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
				if(clipNode){ // may be null if not in the DOM anymore
					clipNode.removeChild(clipNode.childNodes[0]);
				}
			}
			if(clip){
				if(clipNode){
					clipShape = _createElementNS(svg.xmlns.svg, clipType);
					clipNode.appendChild(clipShape);
				}else{
					var idIndex = ++clipCount;
					var clipId = "gfx_clip" + idIndex;
					var clipUrl = "url(#" + clipId + ")";
					this.rawNode.setAttribute("clip-path", clipUrl);
					clipNode = _createElementNS(svg.xmlns.svg, "clipPath");
					clipShape = _createElementNS(svg.xmlns.svg, clipType);
					clipNode.appendChild(clipShape);
					this.rawNode.parentNode.insertBefore(clipNode, this.rawNode);
					domAttr.set(clipNode, "id", clipId);
				}
				domAttr.set(clipShape, clip);
			}else{
				//remove clip-path
				this.rawNode.removeAttribute("clip-path");
				if(clipNode){
					clipNode.parentNode.removeChild(clipNode);
				}
			}
			return this;
		},
		_removeClipNode: function(){
			var clipNode, clipPathProp = domAttr.get(this.rawNode, "clip-path");
			if(clipPathProp){
				clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
				if(clipNode){
					clipNode.parentNode.removeChild(clipNode);
				}
			}
			return clipNode;
		}
	});


	svg.Group = declare("dojox.gfx.svg.Group", svg.Shape, {
		// summary:
		//		a group shape (SVG), which can be used
		//		to logically group shapes (e.g, to propagate matricies)
		constructor: function(){
			gs.Container._init.call(this);
		},
		setRawNode: function(rawNode){
			// summary:
			//		sets a raw SVG node to be used by this shape
			// rawNode: Node
			//		an SVG node
			this.rawNode = rawNode;
			// Bind GFX object with SVG node for ease of retrieval - that is to
			// save code/performance to keep this association elsewhere
			this.rawNode.__gfxObject__ = this;
		},
		destroy: function(){
			// summary:
			//		Releases all internal resources owned by this shape. Once this method has been called,
			//		the instance is considered disposed and should not be used anymore.
			this.clear(true);
			// avoid this.inherited
			svg.Shape.prototype.destroy.apply(this, arguments);
		}
	});
	svg.Group.nodeType = "g";

	svg.Rect = declare("dojox.gfx.svg.Rect", [svg.Shape, gs.Rect], {
		// summary:
		//		a rectangle shape (SVG)
		setShape: function(newShape){
			// summary:
			//		sets a rectangle shape object (SVG)
			// newShape: Object
			//		a rectangle shape object
			this.shape = g.makeParameters(this.shape, newShape);
			this.bbox = null;
			for(var i in this.shape){
				if(i != "type" && i != "r"){
					var v = this.shape[i];
					if(i === "width" || i === "height"){
						v = v < 0 ? 0 : v;
					}
					this.rawNode.setAttribute(i, v);
				}
			}
			if(this.shape.r != null){
				this.rawNode.setAttribute("ry", this.shape.r);
				this.rawNode.setAttribute("rx", this.shape.r);
			}
			return this;	// self
		}
	});
	svg.Rect.nodeType = "rect";

	svg.Ellipse = declare("dojox.gfx.svg.Ellipse", [svg.Shape, gs.Ellipse], {});
	svg.Ellipse.nodeType = "ellipse";

	svg.Circle = declare("dojox.gfx.svg.Circle", [svg.Shape, gs.Circle], {});
	svg.Circle.nodeType = "circle";

	svg.Line = declare("dojox.gfx.svg.Line", [svg.Shape, gs.Line], {});
	svg.Line.nodeType = "line";

	svg.Polyline = declare("dojox.gfx.svg.Polyline", [svg.Shape, gs.Polyline], {
		// summary:
		//		a polyline/polygon shape (SVG)
		setShape: function(points, closed){
			// summary:
			//		sets a polyline/polygon shape object (SVG)
			// points: Object|Array
			//		a polyline/polygon shape object, or an array of points
			if(points && points instanceof Array){
				this.shape = g.makeParameters(this.shape, { points: points });
				if(closed && this.shape.points.length){
					this.shape.points.push(this.shape.points[0]);
				}
			}else{
				this.shape = g.makeParameters(this.shape, points);
			}
			this.bbox = null;
			this._normalizePoints();
			var attr = [], p = this.shape.points;
			for(var i = 0; i < p.length; ++i){
				attr.push(p[i].x.toFixed(8), p[i].y.toFixed(8));
			}
			this.rawNode.setAttribute("points", attr.join(" "));
			return this;	// self
		}
	});
	svg.Polyline.nodeType = "polyline";

	svg.Image = declare("dojox.gfx.svg.Image", [svg.Shape, gs.Image], {
		// summary:
		//		an image (SVG)
		setShape: function(newShape){
			// summary:
			//		sets an image shape object (SVG)
			// newShape: Object
			//		an image shape object
			this.shape = g.makeParameters(this.shape, newShape);
			this.bbox = null;
			var rawNode = this.rawNode;
			for(var i in this.shape){
				if(i != "type" && i != "src"){
					var v = this.shape[i];
					if(i === "width" || i === "height"){
						v = v < 0 ? 0 : v;
					}
					rawNode.setAttribute(i, v);
				}
			}
			rawNode.setAttribute("preserveAspectRatio", "none");
			_setAttributeNS(rawNode, svg.xmlns.xlink, "xlink:href", this.shape.src);
			// Bind GFX object with SVG node for ease of retrieval - that is to
			// save code/performance to keep this association elsewhere
			rawNode.__gfxObject__ = this;
			return this;	// self
		}
	});
	svg.Image.nodeType = "image";

	svg.Text = declare("dojox.gfx.svg.Text", [svg.Shape, gs.Text], {
		// summary:
		//		an anchored text (SVG)
		setShape: function(newShape){
			// summary:
			//		sets a text shape object (SVG)
			// newShape: Object
			//		a text shape object
			this.shape = g.makeParameters(this.shape, newShape);
			this.bbox = null;
			var r = this.rawNode, s = this.shape;
			r.setAttribute("x", s.x);
			r.setAttribute("y", s.y);
			r.setAttribute("text-anchor", s.align);
			r.setAttribute("text-decoration", s.decoration);
			r.setAttribute("rotate", s.rotated ? 90 : 0);
			r.setAttribute("kerning", s.kerning ? "auto" : 0);
			r.setAttribute("text-rendering", textRenderingFix);

			// update the text content
			if(r.firstChild){
				r.firstChild.nodeValue = s.text;
			}else{
				r.appendChild(_createTextNode(s.text));
			}
			return this;	// self
		},
		getTextWidth: function(){
			// summary:
			//		get the text width in pixels
			var rawNode = this.rawNode,
				oldParent = rawNode.parentNode,
				_measurementNode = rawNode.cloneNode(true);
			_measurementNode.style.visibility = "hidden";

			// solution to the "orphan issue" in FF
			var _width = 0, _text = _measurementNode.firstChild.nodeValue;
			oldParent.appendChild(_measurementNode);

			// solution to the "orphan issue" in Opera
			// (nodeValue == "" hangs firefox)
			if(_text!=""){
				while(!_width){
//Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
if (_measurementNode.getBBox)
					_width = parseInt(_measurementNode.getBBox().width);
else
	_width = 68;
				}
			}
			oldParent.removeChild(_measurementNode);
			return _width;
		},
		getBoundingBox: function(){
			var s = this.getShape(), bbox = null;
			if(s.text){
				// try/catch the FF native getBBox error.
				try {
					bbox = this.rawNode.getBBox();
				} catch (e) {
					// under FF when the node is orphan (all other browsers return a 0ed bbox.
					bbox = {x:0, y:0, width:0, height:0};
				}
			}
			return bbox;
		}
	});
	svg.Text.nodeType = "text";

	svg.Path = declare("dojox.gfx.svg.Path", [svg.Shape, pathLib.Path], {
		// summary:
		//		a path shape (SVG)
		_updateWithSegment: function(segment){
			// summary:
			//		updates the bounding box of path with new segment
			// segment: Object
			//		a segment
			this.inherited(arguments);
			if(typeof(this.shape.path) == "string"){
				this.rawNode.setAttribute("d", this.shape.path);
			}
		},
		setShape: function(newShape){
			// summary:
			//		forms a path using a shape (SVG)
			// newShape: Object
			//		an SVG path string or a path object (see dojox/gfx.defaultPath)
			this.inherited(arguments);
			if(this.shape.path){
				this.rawNode.setAttribute("d", this.shape.path);
			}else{
				this.rawNode.removeAttribute("d");
			}
			return this;	// self
		}
	});
	svg.Path.nodeType = "path";

	svg.TextPath = declare("dojox.gfx.svg.TextPath", [svg.Shape, pathLib.TextPath], {
		// summary:
		//		a textpath shape (SVG)
		_updateWithSegment: function(segment){
			// summary:
			//		updates the bounding box of path with new segment
			// segment: Object
			//		a segment
			this.inherited(arguments);
			this._setTextPath();
		},
		setShape: function(newShape){
			// summary:
			//		forms a path using a shape (SVG)
			// newShape: Object
			//		an SVG path string or a path object (see dojox/gfx.defaultPath)
			this.inherited(arguments);
			this._setTextPath();
			return this;	// self
		},
		_setTextPath: function(){
			if(typeof this.shape.path != "string"){ return; }
			var r = this.rawNode;
			if(!r.firstChild){
				var tp = _createElementNS(svg.xmlns.svg, "textPath"),
					tx = _createTextNode("");
				tp.appendChild(tx);
				r.appendChild(tp);
			}
			var ref  = r.firstChild.getAttributeNS(svg.xmlns.xlink, "href"),
				path = ref && svg.getRef(ref);
			if(!path){
				var surface = this._getParentSurface();
				if(surface){
					var defs = surface.defNode;
					path = _createElementNS(svg.xmlns.svg, "path");
					var id = g._base._getUniqueId();
					path.setAttribute("id", id);
					defs.appendChild(path);
					_setAttributeNS(r.firstChild, svg.xmlns.xlink, "xlink:href", "#" + id);
				}
			}
			if(path){
				path.setAttribute("d", this.shape.path);
			}
		},
		_setText: function(){
			var r = this.rawNode;
			if(!r.firstChild){
				var tp = _createElementNS(svg.xmlns.svg, "textPath"),
					tx = _createTextNode("");
				tp.appendChild(tx);
				r.appendChild(tp);
			}
			r = r.firstChild;
			var t = this.text;
			r.setAttribute("alignment-baseline", "middle");
			switch(t.align){
				case "middle":
					r.setAttribute("text-anchor", "middle");
					r.setAttribute("startOffset", "50%");
					break;
				case "end":
					r.setAttribute("text-anchor", "end");
					r.setAttribute("startOffset", "100%");
					break;
				default:
					r.setAttribute("text-anchor", "start");
					r.setAttribute("startOffset", "0%");
					break;
			}
			//r.parentNode.setAttribute("alignment-baseline", "central");
			//r.setAttribute("dominant-baseline", "central");
			r.setAttribute("baseline-shift", "0.5ex");
			r.setAttribute("text-decoration", t.decoration);
			r.setAttribute("rotate", t.rotated ? 90 : 0);
			r.setAttribute("kerning", t.kerning ? "auto" : 0);
			r.firstChild.data = t.text;
		}
	});
	svg.TextPath.nodeType = "text";

	// Fix for setDimension bug:
	// http://bugs.dojotoolkit.org/ticket/16100
	// (https://code.google.com/p/chromium/issues/detail?id=162628)
	var hasSvgSetAttributeBug = (function(){ var matches = /WebKit\/(\d*)/.exec(uagent); return matches ? matches[1] : 0})() > 534;

	svg.Surface = declare("dojox.gfx.svg.Surface", gs.Surface, {
		// summary:
		//		a surface object to be used for drawings (SVG)
		constructor: function(){
			gs.Container._init.call(this);
		},
		destroy: function(){
			// no need to call svg.Container.clear to remove the children raw
			// nodes since the surface raw node will be removed. So, only dispose at gfx level	
			gs.Container.clear.call(this, true); 
			this.defNode = null;	// release the external reference
			this.inherited(arguments);
		},
		setDimensions: function(width, height){
			// summary:
			//		sets the width and height of the rawNode
			// width: String
			//		width of surface, e.g., "100px"
			// height: String
			//		height of surface, e.g., "100px"
			if(!this.rawNode){ return this; }
			var w = width < 0 ? 0 : width,
				h = height < 0 ? 0 : height;
			this.rawNode.setAttribute("width",  w);
			this.rawNode.setAttribute("height", h);
			if(hasSvgSetAttributeBug){
				this.rawNode.style.width =  w;
				this.rawNode.style.height =  h;
			}
			return this;	// self
		},
		getDimensions: function(){
			// summary:
			//		returns an object with properties "width" and "height"
			var t = this.rawNode ? {
				width:  g.normalizedLength(this.rawNode.getAttribute("width")),
				height: g.normalizedLength(this.rawNode.getAttribute("height"))} : null;
			return t;	// Object
		}
	});

	svg.createSurface = function(parentNode, width, height){
		// summary:
		//		creates a surface (SVG)
		// parentNode: Node
		//		a parent node
		// width: String|Number
		//		width of surface, e.g., "100px" or 100
		// height: String|Number
		//		height of surface, e.g., "100px" or 100
		// returns: dojox/gfx/shape.Surface
		//     newly created surface

		var s = new svg.Surface();
		s.rawNode = _createElementNS(svg.xmlns.svg, "svg");
		s.rawNode.setAttribute("overflow", "hidden");
		if(width){
			s.rawNode.setAttribute("width",  width < 0 ? 0 : width);
		}
		if(height){
			s.rawNode.setAttribute("height", height < 0 ? 0 : height);
		}

		var defNode = _createElementNS(svg.xmlns.svg, "defs");
		s.rawNode.appendChild(defNode);
		s.defNode = defNode;

		s._parent = dom.byId(parentNode);
		s._parent.appendChild(s.rawNode);

		g._base._fixMsTouchAction(s);

		return s;	// dojox/gfx.Surface
	};

	// Extenders

	var Font = {
		_setFont: function(){
			// summary:
			//		sets a font object (SVG)
			var f = this.fontStyle;
			// next line doesn't work in Firefox 2 or Opera 9
			//this.rawNode.setAttribute("font", dojox.gfx.makeFontString(this.fontStyle));
			this.rawNode.setAttribute("font-style", f.style);
			this.rawNode.setAttribute("font-variant", f.variant);
			this.rawNode.setAttribute("font-weight", f.weight);
			this.rawNode.setAttribute("font-size", f.size);
			this.rawNode.setAttribute("font-family", f.family);
		}
	};

	var C = gs.Container;
	var Container = svg.Container = {
		openBatch: function() {
			// summary:
			//		starts a new batch, subsequent new child shapes will be held in
			//		the batch instead of appending to the container directly
			if(!this._batch){
				this.fragment = _createFragment();
			}
			++this._batch;
			return this;
		},
		closeBatch: function() {
			// summary:
			//		submits the current batch, append all pending child shapes to DOM
			this._batch = this._batch > 0 ? --this._batch : 0;
			if (this.fragment && !this._batch) {
				this.rawNode.appendChild(this.fragment);
				delete this.fragment;
			}
			return this;
		},
		add: function(shape){
			// summary:
			//		adds a shape to a group/surface
			// shape: dojox/gfx/shape.Shape
			//		an VML shape object
			if(this != shape.getParent()){
				if (this.fragment) {
					this.fragment.appendChild(shape.rawNode);
				} else {
					this.rawNode.appendChild(shape.rawNode);
				}
				C.add.apply(this, arguments);
				// update clipnode with new parent
				shape.setClip(shape.clip);
			}
			return this;	// self
		},
		remove: function(shape, silently){
			// summary:
			//		remove a shape from a group/surface
			// shape: dojox/gfx/shape.Shape
			//		an VML shape object
			// silently: Boolean?
			//		if true, regenerate a picture
			if(this == shape.getParent()){
				if(this.rawNode == shape.rawNode.parentNode){
					this.rawNode.removeChild(shape.rawNode);
				}
				if(this.fragment && this.fragment == shape.rawNode.parentNode){
					this.fragment.removeChild(shape.rawNode);
				}
				// remove clip node from parent 
				shape._removeClipNode();
				C.remove.apply(this, arguments);
			}
			return this;	// self
		},
		clear: function(){
			// summary:
			//		removes all shapes from a group/surface
			var r = this.rawNode;
			while(r.lastChild){
				r.removeChild(r.lastChild);
			}
			var defNode = this.defNode;
			if(defNode){
				while(defNode.lastChild){
					defNode.removeChild(defNode.lastChild);
				}
				r.appendChild(defNode);
			}
			return C.clear.apply(this, arguments);
		},
		getBoundingBox: C.getBoundingBox,
		_moveChildToFront: C._moveChildToFront,
		_moveChildToBack:  C._moveChildToBack
	};

	var Creator = svg.Creator = {
		// summary:
		//		SVG shape creators
		createObject: function(shapeType, rawShape){
			// summary:
			//		creates an instance of the passed shapeType class
			// shapeType: Function
			//		a class constructor to create an instance of
			// rawShape: Object
			//		properties to be passed in to the classes "setShape" method
			if(!this.rawNode){ return null; }
			var shape = new shapeType(),
				node = _createElementNS(svg.xmlns.svg, shapeType.nodeType);

			shape.setRawNode(node);
			shape.setShape(rawShape);
			// rawNode.appendChild() will be done inside this.add(shape) below
			this.add(shape);
			return shape;	// dojox/gfx/shape.Shape
		}
	};

	lang.extend(svg.Text, Font);
	lang.extend(svg.TextPath, Font);

	lang.extend(svg.Group, Container);
	lang.extend(svg.Group, gs.Creator);
	lang.extend(svg.Group, Creator);

	lang.extend(svg.Surface, Container);
	lang.extend(svg.Surface, gs.Creator);
	lang.extend(svg.Surface, Creator);

	// Mouse/Touch event
	svg.fixTarget = function(event, gfxElement) {
		// summary:
		//		Adds the gfxElement to event.gfxTarget if none exists. This new
		//		property will carry the GFX element associated with this event.
		// event: Object
		//		The current input event (MouseEvent or TouchEvent)
		// gfxElement: Object
		//		The GFX target element
		if (!event.gfxTarget) {
			if (safMobile && event.target.wholeText) {
				// Workaround iOS bug when touching text nodes
				event.gfxTarget = event.target.parentElement.__gfxObject__;
			} else {
				event.gfxTarget = event.target.__gfxObject__;
			}
		}
		return true;
	};

	// some specific override for svgweb + flash
	if(svg.useSvgWeb){
		// override createSurface()
		svg.createSurface = function(parentNode, width, height){
			var s = new svg.Surface();
			
			width = width < 0 ? 0 : width;
			height = height < 0 ? 0 : height;

			// ensure width / height
			if(!width || !height){
				var pos = domGeom.position(parentNode);
				width  = width  || pos.w;
				height = height || pos.h;
			}

			// ensure id
			parentNode = dom.byId(parentNode);
			var id = parentNode.id ? parentNode.id+'_svgweb' : g._base._getUniqueId();

			// create dynamic svg root
			var mockSvg = _createElementNS(svg.xmlns.svg, 'svg');
			mockSvg.id = id;
			mockSvg.setAttribute('width', width);
			mockSvg.setAttribute('height', height);
			svgweb.appendChild(mockSvg, parentNode);

			// notice: any call to the raw node before flash init will fail.
			mockSvg.addEventListener('SVGLoad', function(){
				// become loaded
				s.rawNode = this;
				s.isLoaded = true;

				// init defs
				var defNode = _createElementNS(svg.xmlns.svg, "defs");
				s.rawNode.appendChild(defNode);
				s.defNode = defNode;

				// notify application
				if (s.onLoad)
					s.onLoad(s);
			}, false);

			// flash not loaded yet
			s.isLoaded = false;
			return s;
		};

		// override Surface.destroy()
		svg.Surface.extend({
			destroy: function(){
				var mockSvg = this.rawNode;
				svgweb.removeChild(mockSvg, mockSvg.parentNode);
			}
		});

		// override connect() & disconnect() for Shape & Surface event processing
		var _eventsProcessing = {
			connect: function(name, object, method){
				// connect events using the mock addEventListener() provided by svgweb
				if (name.substring(0, 2)==='on') { name = name.substring(2); }
				if (arguments.length == 2) {
					method = object;
				} else {
					method = lang.hitch(object, method);
				}
				this.getEventSource().addEventListener(name, method, false);
				return [this, name, method];
			},
			disconnect: function(token){
				// disconnect events using the mock removeEventListener() provided by svgweb
				this.getEventSource().removeEventListener(token[1], token[2], false);
				delete token[0];
			}
		};

		lang.extend(svg.Shape, _eventsProcessing);
		lang.extend(svg.Surface, _eventsProcessing);
	}

	return svg;
});

},
'dojox/gfx/path':function(){
define(["./_base", "dojo/_base/lang","dojo/_base/declare", "./matrix", "./shape"],
	function(g, lang, declare, matrix, shapeLib){

	// module:
	//		dojox/gfx/path

	var Path = declare("dojox.gfx.path.Path", shapeLib.Shape, {
		// summary:
		//		a generalized path shape

		constructor: function(rawNode){
			// summary:
			//		a path constructor
			// rawNode: Node
			//		a DOM node to be used by this path object
			this.shape = lang.clone(g.defaultPath);
			this.segments = [];
			this.tbbox = null;
			this.absolute = true;
			this.last = {};
			this.rawNode = rawNode;
			this.segmented = false;
		},

		// mode manipulations
		setAbsoluteMode: function(mode){
			// summary:
			//		sets an absolute or relative mode for path points
			// mode: Boolean
			//		true/false or "absolute"/"relative" to specify the mode
			this._confirmSegmented();
			this.absolute = typeof mode == "string" ? (mode == "absolute") : mode;
			return this; // self
		},
		getAbsoluteMode: function(){
			// summary:
			//		returns a current value of the absolute mode
			this._confirmSegmented();
			return this.absolute; // Boolean
		},

		getBoundingBox: function(){
			// summary:
			//		returns the bounding box {x, y, width, height} or null
			this._confirmSegmented();
			return (this.bbox && ("l" in this.bbox)) ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // dojox/gfx.Rectangle
		},

		_getRealBBox: function(){
			// summary:
			//		returns an array of four points or null
			//		four points represent four corners of the untransformed bounding box
			this._confirmSegmented();
			if(this.tbbox){
				return this.tbbox;	// Array
			}
			var bbox = this.bbox, matrix = this._getRealMatrix();
			this.bbox = null;
			for(var i = 0, len = this.segments.length; i < len; ++i){
				this._updateWithSegment(this.segments[i], matrix);
			}
			var t = this.bbox;
			this.bbox = bbox;
			this.tbbox = t ? [
				{x: t.l, y: t.t},
				{x: t.r, y: t.t},
				{x: t.r, y: t.b},
				{x: t.l, y: t.b}
			] : null;
			return this.tbbox;	// Array
		},

		getLastPosition: function(){
			// summary:
			//		returns the last point in the path, or null
			this._confirmSegmented();
			return "x" in this.last ? this.last : null; // Object
		},

		_applyTransform: function(){
			this.tbbox = null;
			return this.inherited(arguments);
		},

		// segment interpretation
		_updateBBox: function(x, y, m){
			// summary:
			//		updates the bounding box of path with new point
			// x: Number
			//		an x coordinate
			// y: Number
			//		a y coordinate

			if(m){
				var t = matrix.multiplyPoint(m, x, y);
				x = t.x;
				y = t.y;
			}

			// we use {l, b, r, t} representation of a bbox
			if(this.bbox && ("l" in this.bbox)){
				if(this.bbox.l > x) this.bbox.l = x;
				if(this.bbox.r < x) this.bbox.r = x;
				if(this.bbox.t > y) this.bbox.t = y;
				if(this.bbox.b < y) this.bbox.b = y;
			}else{
				this.bbox = {l: x, b: y, r: x, t: y};
			}
		},
		_updateWithSegment: function(segment, matrix){
			// summary:
			//		updates the bounding box of path with new segment
			// segment: Object
			//		a segment
			var n = segment.args, l = n.length, i;
			// update internal variables: bbox, absolute, last
			switch(segment.action){
				case "M":
				case "L":
				case "C":
				case "S":
				case "Q":
				case "T":
					for(i = 0; i < l; i += 2){
						this._updateBBox(n[i], n[i + 1], matrix);
					}
					this.last.x = n[l - 2];
					this.last.y = n[l - 1];
					this.absolute = true;
					break;
				case "H":
					for(i = 0; i < l; ++i){
						this._updateBBox(n[i], this.last.y, matrix);
					}
					this.last.x = n[l - 1];
					this.absolute = true;
					break;
				case "V":
					for(i = 0; i < l; ++i){
						this._updateBBox(this.last.x, n[i], matrix);
					}
					this.last.y = n[l - 1];
					this.absolute = true;
					break;
				case "m":
					var start = 0;
					if(!("x" in this.last)){
						this._updateBBox(this.last.x = n[0], this.last.y = n[1], matrix);
						start = 2;
					}
					for(i = start; i < l; i += 2){
						this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);
					}
					this.absolute = false;
					break;
				case "l":
				case "t":
					for(i = 0; i < l; i += 2){
						this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);
					}
					this.absolute = false;
					break;
				case "h":
					for(i = 0; i < l; ++i){
						this._updateBBox(this.last.x += n[i], this.last.y, matrix);
					}
					this.absolute = false;
					break;
				case "v":
					for(i = 0; i < l; ++i){
						this._updateBBox(this.last.x, this.last.y += n[i], matrix);
					}
					this.absolute = false;
					break;
				case "c":
					for(i = 0; i < l; i += 6){
						this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);
						this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3], matrix);
						this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5], matrix);
					}
					this.absolute = false;
					break;
				case "s":
				case "q":
					for(i = 0; i < l; i += 4){
						this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);
						this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3], matrix);
					}
					this.absolute = false;
					break;
				case "A":
					for(i = 0; i < l; i += 7){
						this._updateBBox(n[i + 5], n[i + 6], matrix);
					}
					this.last.x = n[l - 2];
					this.last.y = n[l - 1];
					this.absolute = true;
					break;
				case "a":
					for(i = 0; i < l; i += 7){
						this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6], matrix);
					}
					this.absolute = false;
					break;
			}
			// add an SVG path segment
			var path = [segment.action];
			for(i = 0; i < l; ++i){
				path.push(g.formatNumber(n[i], true));
			}
			if(typeof this.shape.path == "string"){
				this.shape.path += path.join("");
			}else{
				for(i = 0, l = path.length; i < l; ++i){
					this.shape.path.push(path[i]);
				}
			}
		},

		// a dictionary, which maps segment type codes to a number of their arguments
		_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},

		_pushSegment: function(action, args){
			// summary:
			//		adds a segment
			// action: String
			//		valid SVG code for a segment's type
			// args: Array
			//		a list of parameters for this segment
			this.tbbox = null;
			var group = this._validSegments[action.toLowerCase()], segment;
			if(typeof group == "number"){
				if(group){
					if(args.length >= group){
						segment = {action: action, args: args.slice(0, args.length - args.length % group)};
						this.segments.push(segment);
						this._updateWithSegment(segment);
					}
				}else{
					segment = {action: action, args: []};
					this.segments.push(segment);
					this._updateWithSegment(segment);
				}
			}
		},

		_collectArgs: function(array, args){
			// summary:
			//		converts an array of arguments to plain numeric values
			// array: Array
			//		an output argument (array of numbers)
			// args: Array
			//		an input argument (can be values of Boolean, Number, dojox/gfx.Point, or an embedded array of them)
			for(var i = 0; i < args.length; ++i){
				var t = args[i];
				if(typeof t == "boolean"){
					array.push(t ? 1 : 0);
				}else if(typeof t == "number"){
					array.push(t);
				}else if(t instanceof Array){
					this._collectArgs(array, t);
				}else if("x" in t && "y" in t){
					array.push(t.x, t.y);
				}
			}
		},

		// segments
		moveTo: function(){
			// summary:
			//		forms a move segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "M" : "m", args);
			return this; // self
		},
		lineTo: function(){
			// summary:
			//		forms a line segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "L" : "l", args);
			return this; // self
		},
		hLineTo: function(){
			// summary:
			//		forms a horizontal line segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "H" : "h", args);
			return this; // self
		},
		vLineTo: function(){
			// summary:
			//		forms a vertical line segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "V" : "v", args);
			return this; // self
		},
		curveTo: function(){
			// summary:
			//		forms a curve segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "C" : "c", args);
			return this; // self
		},
		smoothCurveTo: function(){
			// summary:
			//		forms a smooth curve segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "S" : "s", args);
			return this; // self
		},
		qCurveTo: function(){
			// summary:
			//		forms a quadratic curve segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "Q" : "q", args);
			return this; // self
		},
		qSmoothCurveTo: function(){
			// summary:
			//		forms a quadratic smooth curve segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "T" : "t", args);
			return this; // self
		},
		arcTo: function(){
			// summary:
			//		forms an elliptic arc segment
			this._confirmSegmented();
			var args = [];
			this._collectArgs(args, arguments);
			this._pushSegment(this.absolute ? "A" : "a", args);
			return this; // self
		},
		closePath: function(){
			// summary:
			//		closes a path
			this._confirmSegmented();
			this._pushSegment("Z", []);
			return this; // self
		},

		_confirmSegmented: function() {
			if (!this.segmented) {
				var path = this.shape.path;
				// switch to non-updating version of path building
				this.shape.path = [];
				this._setPath(path);
				// switch back to the string path
				this.shape.path = this.shape.path.join("");
				// become segmented
				this.segmented = true;
			}
		},

		// setShape
		_setPath: function(path){
			// summary:
			//		forms a path using an SVG path string
			// path: String
			//		an SVG path string
			var p = lang.isArray(path) ? path : path.match(g.pathSvgRegExp);
			this.segments = [];
			this.absolute = true;
			this.bbox = {};
			this.last = {};
			if(!p) return;
			// create segments
			var action = "",	// current action
				args = [],		// current arguments
				l = p.length;
			for(var i = 0; i < l; ++i){
				var t = p[i], x = parseFloat(t);
				if(isNaN(x)){
					if(action){
						this._pushSegment(action, args);
					}
					args = [];
					action = t;
				}else{
					args.push(x);
				}
			}
			this._pushSegment(action, args);
		},
		setShape: function(newShape){
			// summary:
			//		forms a path using a shape
			// newShape: Object
			//		an SVG path string or a path object (see dojox/gfx.defaultPath)
			this.inherited(arguments, [typeof newShape == "string" ? {path: newShape} : newShape]);

			this.segmented = false;
			this.segments = [];
			if(!g.lazyPathSegmentation){
				this._confirmSegmented();
			}
			return this; // self
		},

		// useful constant for descendants
		_2PI: Math.PI * 2
	});

	var TextPath = declare("dojox.gfx.path.TextPath", Path, {
		// summary:
		//		a generalized TextPath shape

		constructor: function(rawNode){
			// summary:
			//		a TextPath shape constructor
			// rawNode: Node
			//		a DOM node to be used by this TextPath object
			if(!("text" in this)){
				this.text = lang.clone(g.defaultTextPath);
			}
			if(!("fontStyle" in this)){
				this.fontStyle = lang.clone(g.defaultFont);
			}
		},
		getText: function(){
			// summary:
			//		returns the current text object or null
			return this.text;	// Object
		},
		setText: function(newText){
			// summary:
			//		sets a text to be drawn along the path
			this.text = g.makeParameters(this.text,
				typeof newText == "string" ? {text: newText} : newText);
			this._setText();
			return this;	// self
		},
		getFont: function(){
			// summary:
			//		returns the current font object or null
			return this.fontStyle;	// Object
		},
		setFont: function(newFont){
			// summary:
			//		sets a font for text
			this.fontStyle = typeof newFont == "string" ?
				g.splitFontString(newFont) :
				g.makeParameters(g.defaultFont, newFont);
			this._setFont();
			return this;	// self
		}
	});

	/*=====
	g.Path = Path;
	g.TextPath = TextPath;
	=====*/

	return g.path = {
		// summary:
		//		This module contains the core graphics Path API.
		//		Path command format follows the W3C SVG 1.0 Path api.

		Path: Path,
		TextPath: TextPath
	};
});

}}});
define("dojo/pmbmaps", [], 1);