text: define("dojox/json/ref", [
  	"dojo/_base/array",
  	"dojo/_base/json",
  	"dojo/_base/kernel", 
  	"dojo/_base/lang",
  	"dojo/date/stamp",
  	"dojox"
  ],
  function(array, djson, dojo, lang, stamp, dojox){
  
  lang.getObject("json", true, dojox);
  
  return dojox.json.ref = {
  	// summary:
  	//		Adds advanced JSON {de}serialization capabilities to the base json library.
  	//		This enhances the capabilities of dojo.toJson and dojo.fromJson,
  	//		adding referencing support, date handling, and other extra format handling.
  	//		On parsing, references are resolved. When references are made to
  	//		ids/objects that have been loaded yet, the loader function will be set to
  	//		_loadObject to denote a lazy loading (not loaded yet) object.
  
  
  	resolveJson: function(/*Object*/ root, /*Object?*/ args){
  		// summary:
  		//		Indexes and resolves references in the JSON object.
  		// description:
  		//		A JSON Schema object that can be used to advise the handling of the JSON (defining ids, date properties, urls, etc)
  		// root:
  		//		The root object of the object graph to be processed
  		// args:
  		//		Object with additional arguments:
  		//
  		//		- The *index* parameter:
  		//			This is the index object (map) to use to store an index of all the objects.
  		//			If you are using inter-message referencing, you must provide the same object for each call.
  		//		- The *defaultId* parameter:
  		//			This is the default id to use for the root object (if it doesn't define it's own id)
  		//		- The *idPrefix* parameter:
  		//			This the prefix to use for the ids as they enter the index. This allows multiple tables
  		//			to use ids (that might otherwise collide) that enter the same global index.
  		//			idPrefix should be in the form "/Service/".  For example,
  		//			if the idPrefix is "/Table/", and object is encountered {id:"4",...}, this would go in the
  		//			index as "/Table/4".
  		//		- The *idAttribute* parameter:
  		//			This indicates what property is the identity property. This defaults to "id"
  		//		- The *assignAbsoluteIds* parameter:
  		//			This indicates that the resolveJson should assign absolute ids (__id) as the objects are being parsed.
  		//		- The *schemas* parameter:
  		//			This provides a map of schemas, from which prototypes can be retrieved
  		//		- The *loader* parameter:
  		//			This is a function that is called added to the reference objects that can't be resolved (lazy objects)
  		// returns:
  		//		An object, the result of the processing
  		args = args || {};
  		var idAttribute = args.idAttribute || 'id';
  		var refAttribute = this.refAttribute;
  		var idAsRef = args.idAsRef;
  		var prefix = args.idPrefix || '';
  		var assignAbsoluteIds = args.assignAbsoluteIds;
  		var index = args.index || {}; // create an index if one doesn't exist
  		var timeStamps = args.timeStamps;
  		var ref,reWalk=[];
  		var pathResolveRegex = /^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/;
  		var addProp = this._addProp;
  		var F = function(){};
  		function walk(it, stop, defaultId, needsPrefix, schema, defaultObject){
  			// this walks the new graph, resolving references and making other changes
  		 	var i, update, val, id = idAttribute in it ? it[idAttribute] : defaultId;
  		 	if(idAttribute in it || ((id !== undefined) && needsPrefix)){
  		 		id = (prefix + id).replace(pathResolveRegex,'$2$3');
  		 	}
  		 	var target = defaultObject || it;
  			if(id !== undefined){ // if there is an id available...
  				if(assignAbsoluteIds){
  					it.__id = id;
  				}
  				if(args.schemas && (!(it instanceof Array)) && // won't try on arrays to do prototypes, plus it messes with queries
  		 					(val = id.match(/^(.+\/)[^\.\[]*$/))){ // if it has a direct table id (no paths)
  		 			schema = args.schemas[val[1]];
  				}
  				// if the id already exists in the system, we should use the existing object, and just
  				// update it... as long as the object is compatible
  				if(index[id] && ((it instanceof Array) == (index[id] instanceof Array))){
  					target = index[id];
  					delete target.$ref; // remove this artifact
  					delete target._loadObject;
  					update = true;
  				}else{
  				 	var proto = schema && schema.prototype; // and if has a prototype
  					if(proto){
  						// if the schema defines a prototype, that needs to be the prototype of the object
  						F.prototype = proto;
  						target = new F();
  					}
  				}
  				index[id] = target; // add the prefix, set _id, and index it
  				if(timeStamps){
  					timeStamps[id] = args.time;
  				}
  			}
  			while(schema){
  				var properties = schema.properties;
  				if(properties){
  					for(i in it){
  						var propertyDefinition = properties[i];
  						if(propertyDefinition && propertyDefinition.format == 'date-time' && typeof it[i] == 'string'){
  							it[i] = stamp.fromISOString(it[i]);
  						}
  					}
  				}
  				schema = schema["extends"];
  			}
  			var length = it.length;
  			for(i in it){
  				if(i==length){
  					break;
  				}
  				if(it.hasOwnProperty(i)){
  					val=it[i];
  					if((typeof val =='object') && val && !(val instanceof Date) && i != '__parent'){
  						ref=val[refAttribute] || (idAsRef && val[idAttribute]);
  						if(!ref || !val.__parent){
  							if(it != reWalk){
  								val.__parent = target;
  							}
  						}
  						if(ref){ // a reference was found
  							// make sure it is a safe reference
  							delete it[i];// remove the property so it doesn't resolve to itself in the case of id.propertyName lazy values
  							var path = ref.toString().replace(/(#)([^\.\[])/,'$1.$2').match(/(^([^\[]*\/)?[^#\.\[]*)#?([\.\[].*)?/); // divide along the path
  							if(index[(prefix + ref).replace(pathResolveRegex,'$2$3')]){
  								ref = index[(prefix + ref).replace(pathResolveRegex,'$2$3')];
  							}else if((ref = (path[1]=='$' || path[1]=='this' || path[1]=='') ? root : index[(prefix + path[1]).replace(pathResolveRegex,'$2$3')])){  // a $ indicates to start with the root, otherwise start with an id
  								// if there is a path, we will iterate through the path references
  								if(path[3]){
  									path[3].replace(/(\[([^\]]+)\])|(\.?([^\.\[]+))/g,function(t,a,b,c,d){
  										ref = ref && ref[b ? b.replace(/[\"\'\\]/,'') : d];
  									});
  								}
  							}
  							if(ref){
  								val = ref;
  							}else{
  								// otherwise, no starting point was found (id not found), if stop is set, it does not exist, we have
  								// unloaded reference, if stop is not set, it may be in a part of the graph not walked yet,
  								// we will wait for the second loop
  								if(!stop){
  									var rewalking;
  									if(!rewalking){
  										reWalk.push(target); // we need to rewalk it to resolve references
  									}
  									rewalking = true; // we only want to add it once
  									val = walk(val, false, val[refAttribute], true, propertyDefinition);
  									// create a lazy loaded object
  									val._loadObject = args.loader;
  								}
  							}
  						}else{
  							if(!stop){ // if we are in stop, that means we are in the second loop, and we only need to check this current one,
  								// further walking may lead down circular loops
  								val = walk(
  									val,
  									reWalk==it,
  									id === undefined ? undefined : addProp(id, i), // the default id to use
  									false,
  									propertyDefinition,
  									// if we have an existing object child, we want to
  									// maintain it's identity, so we pass it as the default object
  									target != it && typeof target[i] == 'object' && target[i]
  								);
  							}
  						}
  					}
  					it[i] = val;
  					if(target!=it && !target.__isDirty){// do updates if we are updating an existing object and it's not dirty
  						var old = target[i];
  						target[i] = val; // only update if it changed
  						if(update && val !== old && // see if it is different
  								!target._loadObject && // no updates if we are just lazy loading
  								!(i.charAt(0) == '_' && i.charAt(1) == '_') && i != "$ref" &&
  								!(val instanceof Date && old instanceof Date && val.getTime() == old.getTime()) && // make sure it isn't an identical date
  								!(typeof val == 'function' && typeof old == 'function' && val.toString() == old.toString()) && // make sure it isn't an indentical function
  								index.onUpdate){
  							index.onUpdate(target,i,old,val); // call the listener for each update
  						}
  					}
  				}
  			}
  	
  			if(update && (idAttribute in it || target instanceof Array)){
  				// this means we are updating with a full representation of the object, we need to remove deleted
  				for(i in target){
  					if(!target.__isDirty && target.hasOwnProperty(i) && !it.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && !(target instanceof Array && isNaN(i))){
  						if(index.onUpdate && i != "_loadObject" && i != "_idAttr"){
  							index.onUpdate(target,i,target[i],undefined); // call the listener for each update
  						}
  						delete target[i];
  						while(target instanceof Array && target.length && target[target.length-1] === undefined){
  							// shorten the target if necessary
  							target.length--;
  						}
  					}
  				}
  			}else{
  				if(index.onLoad){
  					index.onLoad(target);
  				}
  			}
  			return target;
  		}
  		if(root && typeof root == 'object'){
  			root = walk(root,false,args.defaultId, true); // do the main walk through
  			walk(reWalk,false); // re walk any parts that were not able to resolve references on the first round
  		}
  		return root;
  	},
  
  
  	fromJson: function(/*String*/ str,/*Object?*/ args){
  	// summary:
  	//		evaluates the passed string-form of a JSON object.
  	// str:
  	//		a string literal of a JSON item, for instance:
  	// |	'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'
  	// args:
  	//		See resolveJson
  	// returns:
  	//		An object, the result of the evaluation
  		function ref(target){ // support call styles references as well
  			var refObject = {};
  			refObject[this.refAttribute] = target;
  			return refObject;
  		}
  		try{
  			var root = eval('(' + str + ')'); // do the eval
  		}catch(e){
  			throw new SyntaxError("Invalid JSON string: " + e.message + " parsing: "+ str);
  		}
  		if(root){
  			return this.resolveJson(root, args);
  		}
  		return root;
  	},
  	
  	toJson: function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*Object?*/ idPrefix, /*Object?*/ indexSubObjects){
  		// summary:
  		//		Create a JSON serialization of an object.
  		//		This has support for referencing, including circular references, duplicate references, and out-of-message references
  		//		id and path-based referencing is supported as well and is based on http://www.json.com/2007/10/19/json-referencing-proposal-and-library/.
  		// it:
  		//		an object to be serialized.
  		// prettyPrint:
  		//		if true, we indent objects and arrays to make the output prettier.
  		//		The variable dojo.toJsonIndentStr is used as the indent string
  		//		-- to use something other than the default (tab),
  		//		change that variable before calling dojo.toJson().
  		// idPrefix:
  		//		The prefix that has been used for the absolute ids
  		// returns:
  		//		a String representing the serialized version of the passed object.
  		var useRefs = this._useRefs;
  		var addProp = this._addProp;
  		var refAttribute = this.refAttribute;
  		idPrefix = idPrefix || ''; // the id prefix for this context
  		var paths={};
  		var generated = {};
  		function serialize(it,path,_indentStr){
  			if(typeof it == 'object' && it){
  				var value;
  				if(it instanceof Date){ // properly serialize dates
  					return '"' + stamp.toISOString(it,{zulu:true}) + '"';
  				}
  				var id = it.__id;
  				if(id){ // we found an identifiable object, we will just serialize a reference to it... unless it is the root
  					if(path != '#' && ((useRefs && !id.match(/#/)) || paths[id])){
  						var ref = id;
  						if(id.charAt(0)!='#'){
  							if(it.__clientId == id){
  								ref = "cid:" + id;
  							}else if(id.substring(0, idPrefix.length) == idPrefix){ // see if the reference is in the current context
  								// a reference with a prefix matching the current context, the prefix should be removed
  								ref = id.substring(idPrefix.length);
  							}else{
  								// a reference to a different context, assume relative url based referencing
  								ref = id;
  							}
  						}
  						var refObject = {};
  						refObject[refAttribute] = ref;
  						return serialize(refObject,'#');
  					}
  					path = id;
  				}else{
  					it.__id = path; // we will create path ids for other objects in case they are circular
  					generated[path] = it;
  				}
  				paths[path] = it;// save it here so they can be deleted at the end
  				_indentStr = _indentStr || "";
  				var nextIndent = prettyPrint ? _indentStr + djson.toJsonIndentStr : "";
  				var newLine = prettyPrint ? "\n" : "";
  				var sep = prettyPrint ? " " : "";
  	
  				if(it instanceof Array){
  					var res = array.map(it, function(obj,i){
  						var val = serialize(obj, addProp(path, i), nextIndent);
  						if(typeof val != "string"){
  							val = "undefined";
  						}
  						return newLine + nextIndent + val;
  					});
  					return "[" + res.join("," + sep) + newLine + _indentStr + "]";
  				}
  	
  				var output = [];
  				for(var i in it){
  					if(it.hasOwnProperty(i)){
  						var keyStr;
  						if(typeof i == "number"){
  							keyStr = '"' + i + '"';
  						}else if(typeof i == "string" && (i.charAt(0) != '_' || i.charAt(1) != '_')){
  							// we don't serialize our internal properties __id and __clientId
  							keyStr = djson._escapeString(i);
  						}else{
  							// skip non-string or number keys
  							continue;
  						}
  						var val = serialize(it[i],addProp(path, i),nextIndent);
  						if(typeof val != "string"){
  							// skip non-serializable values
  							continue;
  						}
  						output.push(newLine + nextIndent + keyStr + ":" + sep + val);
  					}
  				}
  				return "{" + output.join("," + sep) + newLine + _indentStr + "}";
  			}else if(typeof it == "function" && dojox.json.ref.serializeFunctions){
  				return it.toString();
  			}
  	
  			return djson.toJson(it); // use the default serializer for primitives
  		}
  		var json = serialize(it,'#','');
  		if(!indexSubObjects){
  			for(var i in generated)  {// cleanup the temporary path-generated ids
  				delete generated[i].__id;
  			}
  		}
  		return json;
  	},
  	_addProp: function(id, prop){
  		return id + (id.match(/#/) ? id.length == 1 ? '' : '.' : '#') + prop;
  	},
  	// refAttribute: String
  	//		This indicates what property is the reference property. This acts like the idAttribute
  	//		except that this is used to indicate the current object is a reference or only partially
  	//		loaded. This defaults to "$ref".
  	refAttribute: "$ref",
  	_useRefs: false,
  	serializeFunctions: false
  };
  });
  