text: define("dojox/charting/DataSeries", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/connect", "dojox/lang/functional"],
  	function(Lang, declare, ArrayUtil, connect, df){
  
  	return declare("dojox.charting.DataSeries", null, {
  		constructor: function(store, kwArgs, value){
  			// summary:
  			//		Series adapter for dojo.data stores.
  			// store: Object
  			//		A dojo.data store object.
  			// kwArgs: Object
  			//		A store-specific keyword parameters used for fetching items.
  			//		See dojo/data/api/Read.fetch().
  			// value: Function|Object|String
  			//		Function, which takes a store, and an object handle, and
  			//		produces an output possibly inspecting the store's item. Or
  			//		a dictionary object, which tells what names to extract from
  			//		an object and how to map them to an output. Or a string, which
  			//		is a numeric field name to use for plotting. If undefined, null
  			//		or empty string (the default), "value" field is extracted.
  			this.store = store;
  			this.kwArgs = kwArgs;
  	
  			if(value){
  				if(Lang.isFunction(value)){
  					this.value = value;
  				}else if(Lang.isObject(value)){
  					this.value = Lang.hitch(this, "_dictValue",
  						df.keys(value), value);
  				}else{
  					this.value = Lang.hitch(this, "_fieldValue", value);
  				}
  			}else{
  				this.value = Lang.hitch(this, "_defaultValue");
  			}
  	
  			this.data = [];
  	
  			this._events = [];
  	
  			if(this.store.getFeatures()["dojo.data.api.Notification"]){
  				this._events.push(
  					connect.connect(this.store, "onNew", this, "_onStoreNew"),
  					connect.connect(this.store, "onDelete", this, "_onStoreDelete"),
  					connect.connect(this.store, "onSet", this, "_onStoreSet")
  				);
  			}
  
  			this._initialRendering = true;
  			this.fetch();
  		},
  	
  		destroy: function(){
  			// summary:
  			//		Clean up before GC.
  			ArrayUtil.forEach(this._events, connect.disconnect);
  		},
  	
  		setSeriesObject: function(series){
  			// summary:
  			//		Sets a dojox.charting.Series object we will be working with.
  			// series: dojox.charting.Series
  			//		Our interface to the chart.
  			this.series = series;
  		},
  	
  		// value transformers
  	
  		_dictValue: function(keys, dict, store, item){
  			var o = {};
  			ArrayUtil.forEach(keys, function(key){
  				o[key] = store.getValue(item, dict[key]);
  			});
  			return o;
  		},
  	
  		_fieldValue: function(field, store, item){
  			return store.getValue(item, field);
  		},
  	
  		_defaultValue: function(store, item){
  			return store.getValue(item, "value");
  		},
  	
  		// store fetch loop
  	
  		fetch: function(){
  			// summary:
  			//		Fetches data from the store and updates a chart.
  			if(!this._inFlight){
  				this._inFlight = true;
  				var kwArgs = Lang.delegate(this.kwArgs);
  				kwArgs.onComplete = Lang.hitch(this, "_onFetchComplete");
  				kwArgs.onError = Lang.hitch(this, "onFetchError");
  				this.store.fetch(kwArgs);
  			}
  		},
  	
  		_onFetchComplete: function(items, request){
  			this.items = items;
  			this._buildItemMap();
  			this.data = ArrayUtil.map(this.items, function(item){
  				return this.value(this.store, item);
  			}, this);
  			this._pushDataChanges();
  			this._inFlight = false;
  		},
  	
  		onFetchError: function(errorData, request){
  			// summary:
  			//		As stub to process fetch errors. Provide so user can attach to
  			//		it with dojo.connect(). See dojo/data/api/Read fetch() for
  			//		details: onError property.
  			this._inFlight = false;
  		},
  	
  		_buildItemMap: function(){
  			if(this.store.getFeatures()["dojo.data.api.Identity"]){
  				var itemMap = {};
  				ArrayUtil.forEach(this.items, function(item, index){
  					itemMap[this.store.getIdentity(item)] = index;
  				}, this);
  				this.itemMap = itemMap;
  			}
  		},
  	
  		_pushDataChanges: function(){
  			if(this.series){
  				this.series.chart.updateSeries(this.series.name, this, this._initialRendering);
  				this._initialRendering = false;
  				this.series.chart.delayedRender();
  			}
  		},
  	
  		// store notification handlers
  	
  		_onStoreNew: function(){
  			// the only thing we can do is to re-fetch items
  			this.fetch();
  		},
  	
  		_onStoreDelete: function(item){
  			// we cannot do anything with deleted item, the only way is to compare
  			// items for equality
  			if(this.items){
  				var flag = ArrayUtil.some(this.items, function(it, index){
  					if(it === item){
  						this.items.splice(index, 1);
  						this._buildItemMap();
  						this.data.splice(index, 1);
  						return true;
  					}
  					return false;
  				}, this);
  				if(flag){
  					this._pushDataChanges();
  				}
  			}
  		},
  	
  		_onStoreSet: function(item){
  			if(this.itemMap){
  				// we can use our handy item map, if the store supports Identity
  				var id = this.store.getIdentity(item), index = this.itemMap[id];
  				if(typeof index == "number"){
  					this.data[index] = this.value(this.store, this.items[index]);
  					this._pushDataChanges();
  				}
  			}else{
  				// otherwise we have to rely on item's equality
  				if(this.items){
  					var flag = ArrayUtil.some(this.items, function(it, index){
  						if(it === item){
  							this.data[index] = this.value(this.store, it);
  							return true;
  						}
  						return false;
  					}, this);
  					if(flag){
  						this._pushDataChanges();
  					}
  				}
  			}
  		}
  	});
  });
  