(function () {
	if(typeof(vjo)=="object" && vjo._v == 1.3){
		return;
	}
	vjo = {};
	vjo.loader = null;
	vjo._v = 1.3;
	vjo.$static = function (scp) {
		var len = vjo._callStack.length;
		if (len>0) {
			scp = vjo._callStack[len-1];
		}
		var _t = scp._type;
		if (typeof _t == 'string' && _t.indexOf('type')>-1) {
			return scp;
		}
		return scp.constructor;
	}
	vjo.$ns = function (scp) {
		return vjo.$static(scp).b;
	}
	var tmp = vjo._reservedProps = 'props protos inherits prototype inits satisfies bsatisfiers b def mixin mixinProps _inherits _satisfiers _type singleton makeFinal instanceOf endType _class _errors',
	testProp = new RegExp('\\b' + tmp.replace(/ /g,'\\b|\\b')+ '\\b'),
	testInst = /\bconstructs\b|\bgetBase\b|\bbase\b|\bb\b/;
	
	vjo.isValidProp = function (pVal) {
		return !testProp.test(pVal);
	}
	vjo.isValidInst = function (pVal) {
		return !testInst.test(pVal);
	}
	
	vjo.global = this;
	vjo._bScope = null;
	vjo._typeMap = {};
	vjo._callStack = [];
	vjo.createPkg = function(clz) {
		if (!clz) return null;
		if (this._typeMap[clz]) //if have pkg, return
			return this._typeMap[clz]
		var names = clz.split('.'), len = names.length;
		var pkg = this.global; //TODO: update with scope
		for (var i=0;i<len-1 && pkg && names[i];i++){
			pkg = (pkg[names[i]]) ? pkg[names[i]] : pkg[names[i]] = {};
		}
		this._typeMap[clz] = {pkg:pkg,className:(len>0)?names[len-1]:""}
		return this._typeMap[clz];
	};
	
	vjo.needs = function (clz,alias) {
		if (!clz) return;
		if (!this._bScope) {
			this._bScope = {};
		}
		var pObj = this.createPkg(clz), cls = pObj.className,
		tp = pObj.pkg[cls];
		if (!tp) {
			if (this.loader != null)  {
				var tmpScope = this._bScope; //save the current stack
				this._bScope = null;
				this.loader.load(clz);
				this._bScope = tmpScope; //restore the stack
				tp = pObj.pkg[cls];
			}
		}
		if (tp) {
			if (typeof alias == "string" && alias!="") {
				cls = alias;
			}
			this._bScope[cls] = tp;
		
		}
	};
	vjo.needsLib = function () {
	};
	
	vjo._createType = function (clz,isInterface) {
		var oType = vjo.createPkg(clz), bCanInherit = true, _mixinProps = [], _mixins = [];
		var base = function() {
			//assign needed types from class
			//TODO: keeping for backwards compat. can remove after train rollout
			this.b = base.b;
			//add static class name to this.b
		    
			if (!this.constructs) {
				this.constructs = function () {};
			}
			var rv = this.constructs.apply(this,arguments);
			//this.base constructor can no longer be used. just add base methods.
			if (this.base && this.getBase) {//update base, so we're not pointing at shared prototype base
				var fn = function(){};
				fn.prototype = this.getBase();
				this.base = new fn; 
				this.base._parent = this;
			}
			if (rv) {
				return rv;
			}
			// jce: placeholder to fix lint error
			return null;
		};
		base._class = clz;
		base.props = function (obj) {
			for (var i in obj) {	
				if (vjo.isValidProp(i)) {
					base[i] = obj[i];
					//base[i]._type = base;
				}
			}
			return base;
		};
		
		base.protos = function (obj) {
			bCanInherit = false;
			for (var i in obj) {
				if (i!='base' && i!='b') {
					this.prototype[i] = obj[i];
					//this.prototype[i]._type = base;
				}
			}
			return base;
		};
		
		
		base.inherits = function (supClass) { //check order if inherits is called after proto or props
			if (!bCanInherit) { 
				//alert("inherits must be called before protos or mixin"); 
				return this; //error
			};
			if (!isInterface) {
				if (this._inherits) {
					return this; //error - Cannot have more than one inherits!
				} else {
					this._inherits = supClass;
				}
			}
			var type;
			if (this.b) {//lookup to see if it's added in the imports and can be accessed by shorthand
				type = this.b[supClass];
			}
			if (!type) {
				var opkg = vjo.createPkg(supClass);
				type = opkg.pkg[opkg.className];
				if (!type) {
					//error
					return;
				}
			}
			
			if (isInterface)  {
				this.protos(type.prototype);
				this.props(type);			
				bCanInherit = true;	
			} else {//debugger;
				var ptype = type.prototype, tmp = ptype.constructs, tmpBase = ptype.getBase;
				ptype.constructs = null; //don't want constructs to call
				ptype.getBase = null;
				var cls = new type;
				ptype.constructs = tmp; //restore constructs
				ptype.getBase = tmpBase;
				cls.constructor = base;
				var baseRef = {};
				cls.base = function () {
					var cbase = this.base;
					var ptype = type.prototype; 
					if (ptype.base) {
						this.base = ptype.base;
					}
					if (ptype.constructs) {
						ptype.constructs.apply(this,arguments);
					}
					this.base = cbase;
				}
				cls.getBase = function() {
					return baseRef;
				};
				//add protos methods/
				for (var i in ptype) {
					var pt = ptype[i];
					if (vjo.isValidInst(i)) {
						if (typeof pt == 'function' && typeof pt._type == 'undefined') {
							baseRef[i] = (function (type,func) { //create base types
									return function () { //debugger;
										var len = vjo._callStack.length;
										vjo._callStack[len]=type;
										var scp = (this._parent) ? this._parent : this;
										var cbase = scp.base; //keep base instance
										scp.base = (type.prototype.getBase)? type.prototype.getBase() : null;
										if (scp.base) scp.base._parent = scp; //keep toplevel scope
										var rv = func.apply(scp,arguments);
										scp.base = cbase;
										delete vjo._callStack[len];
										vjo._callStack.length = len;
										return rv;
									};
							})(type,pt);
							/*var fnStr = pt.toString();
							if (fnStr.indexOf("_vjProxy2Base_")==-1) {	
								cls[i] = (function (fn) { //create chained methods
									return function _vjProxy2Base_ () {
										return fn.apply(this,arguments);
									}
								})(baseRef[i]);
							} else {
								cls[i] = pt;
							}*/
							var fnStr = pt.toString();
							if (fnStr.indexOf('this.base.'+i+'(')!=-1) {
								cls[i] = (function (fn) { //create chained methods
									return function () {
										return fn.apply(this,arguments);
									}
								})(baseRef[i]);
							} else {
								cls[i] = pt;
							}
						} else {
							cls[i] = pt;
						}
					}
				}
				
				//add props
				for (var i in type) {
					if (vjo.isValidProp(i)) {
						if (typeof type[i] == 'function') {
							baseRef[i] = (function (type,i) { //create base types
									return function () { //debugger;
										//vjo._callStack.push(type);
										var len = vjo._callStack.length;
										vjo._callStack[len]=type;
										var rv = type[i].apply(type,arguments);
										delete vjo._callStack[len];
										vjo._callStack.length = len;
										//vjo._callStack.pop();
										return rv;
										
									};
							})(type,i);
							
							this[i] = (function (fn) { //create chained methods
								return function () {
									return fn.apply(this,arguments);
								}
							})(baseRef[i]);
						} else {
							this[i] = type[i];
						}
					}
				}
				this.prototype = cls;
			} 
	
			return this;
			
		};
		if (!isInterface) {
			base.mixinProps = function (mType) {
				var pObj = vjo.createPkg(mType), mxn = pObj.pkg[pObj.className];
				if (!mxn || mxn._type!='mtype') return base;
				_mixinProps[_mixinProps.length] = mxn._props;
				//TODO: what to do with collisions?
				base.props(mxn._props);
				base._expects = (mxn._expects) ? mxn._expects : null;
				return base;
			};
			
			base.mixin = function (mType) {
				var pObj = vjo.createPkg(mType), mxn = pObj.pkg[pObj.className];
				if (!mxn || mxn._type!='mtype') return base;
				_mixins[_mixins.length] = mxn._protos;
				_mixinProps[_mixinProps.length] = mxn._props;
				//TODO: what to do with collisions?
				base.protos(mxn._protos);
				base.props(mxn._props);
				base._expects = (mxn._expects) ? mxn._expects : null;
				return base;
			};
			base.instanceOf = function (obj) {//debugger;
				//TODO: mac ie 5? need to support? currently tier 3 browser
				return (obj instanceof base);
			}
		}
		
		base.endType = function () {
			if (vjo.validateType) {
				vjo.validateType(this);
			}
		}
		
		return base;
	}
	
	
	vjo.ctype = function (clz) {
		var base = vjo._createType(clz,false);
		base._type = 'ctype';
		base._satisfiers = [];
		base._inherits = null;
		base.singleton = function () {
			//TODO: self instantiate
			return base;
		};
		base.inits = function (func) {
			//the class may have already been created, so there's no need
			//to call static initializer once again.
			var pObj = vjo.createPkg(clz);
			if (typeof pObj.pkg[pObj.className] == 'function') {
				func.call(this);
			}
			return base;
		};
		base.satisfies = function (type) {
			var len = this._satisfiers.length;
			var pObj = vjo.createPkg(type), iface = pObj.pkg[pObj.className];
			if (iface) {
				this._satisfiers[len] = type;
				//if (!testProp.test(i))
				for (var i in iface) {	
					var val = iface[i];
					if (vjo.isValidProp(i) && (typeof val == "number" 
						|| typeof val == "string" || typeof val == "boolean")) {
						base[i] = val;
						//base[i]._type = base;
					}
				}
			}
			
			return base;
		};
		base.makeFinal = function () {
			//TODO:
			return base;
		};
		/*base.create = function () {
			var ptype = base.prototype, tmp = ptype.constructs;
			ptype.constructs = null;
			var inst = new base;
			ptype.constructs = tmp; //restore constructs
			if (ptype.constructs) {
				ptype.constructs.apply(inst,arguments);
			}
			return inst;
		}*/
		//setup shorthand scope, based on needs
		base.b = vjo._bScope;
		vjo._bScope = null;
		
		//if class not specified, return class
		if (!clz) return base;
		
		//if class already exists, just return the type. do not override existing class
		var pObj = vjo.createPkg(clz), tp = (pObj.pkg[pObj.className])? base : (pObj.pkg[pObj.className] = base);
		//if (nmspace) {
		//		nmspace[pObj.className] = tp;
		//}
		return tp; 
	};
	
	vjo.type = vjo.ctype;
	
	vjo.atype = function (clz,nmspace) {
		//should not have a constructor
		var type = this.type(clz,nmspace);
		type._type = 'atype';
		return type;
	}
	
	vjo.itype = function (clz) {
		var base = vjo._createType(clz,true);
		base._type = 'itype';
		base.instanceOf = function (obj) {
				var rv = true, proto = this.prototype;
				for (var prop in proto) {
					if (vjo.isValidInst(prop) && typeof obj[prop] == 'undefined') {
						rv = false;
						break;
					}
				}
				return rv;
		}
		//debugger;
		//if class not specified, return class
		if (!clz) return base;
		
		var pObj = vjo.createPkg(clz);
		//if class already exists, just return the type. do not override existing class
		return (pObj.pkg[pObj.className])? base : (pObj.pkg[pObj.className] = base); 
	};
	
	vjo.mtype = function (clz) {
		var base = {
			_type : 'mtype',
			_props : {},
			_protos : {},
			_expects : "",
			_satisfiers : [],
			props : function (props) {
				addMethods(this._props,props);
				return this;
			},
			protos :  function (protos) {
				addMethods(this._protos,protos);
				return this;
			},
			expects : function (clz) {
				this._expects = clz;
				return this;
			},
			satisfies : function (clz) {
				this._satisfiers[this._satisfiers.length] = clz;
				return this;
			},
			
			endType : function () {
				//TODO - Process mtype endType here...
			}
		};
	
		function addMethods(to, methods) {
			if (!methods || typeof methods != 'object') return;
			for (var i in methods) {
				if (i!='props'&&i!='protos'&&i!='_props'&&i!='_protos'&&i!='type') {
					to[i] = methods[i];
				}
			}
		}
		
		var pObj = vjo.createPkg(clz);
		//if class already exists, just return the type. do not override existing class
		return (pObj.pkg[pObj.className])? base : (pObj.pkg[pObj.className] = base); 
		return base;
	}
	vjo.sysout = {}; //do nothing or proxy to firebug console
	vjo.sysout.print = function() {
		if (typeof console != "undefined") {
			console.info.apply(this, arguments);
		}
	}
	vjo.sysout.println = function() {
		if (typeof console != "undefined") {
			console.info.apply(this, arguments);
		}
	}
	vjo.syserr = {};
	vjo.syserr.print = function() {
		if (typeof console != "undefined") {
			console.warn.apply(this, arguments);
		}
	}
	vjo.syserr.println = function() {
		if (typeof console != "undefined") {
			console.warn.apply(this, arguments);
		}
	}
	vjo.jsunit = {}; //do nothing
	vjo.jsunit.assertEqual = function() {}
	vjo.jsunit.assertTrue = function() {}
	vjo.jsunit.assertFalse = function() {}
})();
 
vjo.ctype('vjo.dsf.Message')
.protos({
	constructs : function (svcId) {
		this.objType = "dsf_Message";
		this.svcId = svcId;
		this.request;
		this.response;
		this.rawRequest = "";
		this.clientContext = {};
		this.trspType = 'InProc';
		this.status;
		this.svcConfig;
		this.returnData = true;
		this.trace = '';
		this.v = '0';
	}
})
.endType();
vjo.ctype("vjo.dsf.Element")
.props({
	//> public String get(String);
	get : function(psId) {
		var d = document, e = null;
		if (typeof(d.getElementById) != "undefined")
			e = d.getElementById(psId);
		else if (!e && d.all)
			e = d.all[psId];
		return e;
	},
	
	//> public void toggleHideShow(String,Boolean);
	toggleHideShow : function(psId, pbDisplay) {
		var e = this.get(psId), s, d, u = "undefined";
		if (e)
		{
			s = e.style;
			d = s.display;
			if (typeof(pbDisplay)===u)
			{
				pbDisplay = (d === "" || d === "block") ? false : true;
			}
			e.bIsShown = pbDisplay;
			s.display = (pbDisplay) ? "block" : "none";
		}	
	},
	
	//> public void promoteToBody(String);
	promoteToBody : function(psId) {
		var e = this.get(psId), b = document.body;
		if(e && b && e.parentNode && (e.parentNode !== b)){
			e.parentNode.removeChild(e);
			b.appendChild(e);
		}
	},
	
	//> public void toggleVisibility(String,Boolean);
	toggleVisibility : function(psId, pbVisible) {
		var e = this.get(psId), v, s, u = "undefined";
		if (e)
		{
			s = e.style;
			v = s.visibility;
			if (typeof(pbVisible)===u)
			{
				pbVisible = (v === "") ? false : true;
			}
			
			e.bIsVisible = pbVisible;
			s.visibility = (pbVisible) ? "" : "hidden";
		}
	},
	
	//> public void enable(String,Boolean);
	enable : function(psId, pbEnable) {
		var e = this.get(psId);
		if (e)
			e.disabled = !pbEnable;
	},
	
	
 
	//> public String left(String,String);
	left : function(psId, psLeft) {
		return this.setLTWH(psId, psLeft, "Left");
	},
	
	//> public String top(String,String);
	top : function(psId, psTop)	{
		return this.setLTWH(psId, psTop, "Top");
	},
	
	//> public String width(String,String);
	width : function(psId, psWidth)	{
		return this.setLTWH(psId, psWidth, "Width");
	},
	
	//> public String height(String,String);
	height : function(psId, psHeight) {
		return this.setLTWH(psId, psHeight, "Height");
	},
	
	//> protected String top(String,String,String);
	setLTWH : function(psId, psVal, psName) {
		var e = this.get(psId);
		if (e)
		{
			if ((psVal != null) && !isNaN(parseInt(psVal)))
				e.style[psName.toLowerCase()] = psVal;
			return e["offset" + psName];
		}
	},
	createElement : function(name) {
		return document.standardCreateElement?document.standardCreateElement(name):document.createElement(name);
	},
 
	containsElement : function(container,element) {
		while ((element != null) && (element != container) && (element.parentNode != null)) { element = element.parentNode; }
		return (element == container);
	},
 
	getElementByTagClass : function(element,tag,name) {
		var tags = element.getElementsByTagName(tag);
		for (var ndx = 0;((ndx < tags.length) && (tags[ndx].className.match(name) == null));ndx++);
		return (ndx < tags.length)?tags[ndx]:null;
	},
 
	getElementsByTagClass : function(element,tag,name) {
		var elements = new Array();
		var tags = element.getElementsByTagName(tag);
		for (var ndx = 0;(ndx < tags.length);ndx++) {
			if (tags[ndx].className.match(name)) elements.push(tags[ndx]);
		}
		return elements;
	}
})
.endType();
 
 
 
 
vjo.ctype('vjo.dsf.Event')
.protos({
	constructs : function (src, eventType, pEvent) {
		this.src = src;
		this.eventType = eventType;
		this.nativeEvent = pEvent;
	}
})
.endType();
//  Manages, dispatches, and cleans up all DOM events created 
//  in V4. EventDispatcher is a singleton. You can access 
//  EventDispatcher directly, via vjo.dsf.EventDispatcher.
 
vjo.needs('vjo.dsf.Event');
vjo.needs('vjo.dsf.Element');
vjo.ctype('vjo.dsf.EventDispatcher')
.singleton()
.protos({
	constructs : function () {
		this.eventHandlers = {};
		this.nativeEventHandlers = {};
		this.unboundElems = [];
		this.fCustomLoad = {};
		this.ns = vjo.$ns(this);
	},
	process : function(srcId, event) {
		var eventHandlersPerSrc = this.eventHandlers[srcId];
		if (!eventHandlersPerSrc) {
			return true;
		}
	
		var handlers = eventHandlersPerSrc[event.eventType];
		if (!handlers) {
			return true;
		}
	
		var returnData;
	
		for (var i = 0; i < handlers.length; i++) {
			var message = handlers[i].handle(event);
			if (message && message.objType == "dsf_Message") {
				if (vjo.dsf.ServiceEngine) {//make async
					//var cb = this.createRequest(message);
					//window.setTimeout(cb,1);
					vjo.dsf.ServiceEngine.handleRequest(message);
				}
				if (message.returnData===false) {
					returnData = false;
				}
			} else if (returnData!=false && typeof message != 'undefined') { //do not ovveride false
				returnData = message;
			} 
		}
			
		return returnData;	
	},
	//createRequest : function (msg) {
	//	return function () {
	//		vjo.dsf.ServiceEngine.handleRequest(msg);
	//	};
	//},
	register : function(id, eventType, handler, scope) {
		if (!id || !eventType || !handler) {
			return this;
		} else {
			if (typeof handler.handle != 'function') {
				if (typeof handler == 'function') {
					var func = handler, scp = scope || this;
					var obj = {handle:function () {
						return func.apply(scp,arguments);
					}};
					handler = obj;
				} else {
					return this;
				}
			}
		}
		
		var handlers = this.eventHandlers[id];
		if (!handlers) {
			handlers = this.eventHandlers[id] = {};
		}
		if (!handlers[eventType]) {
			handlers[eventType] = [];
		}
		var len = handlers[eventType].length;
		handlers[eventType][len] = handler;
		return handler;
	},
	unregister : function (id,eventType) {
		if (!this.eventHandlers[id]) {
			return;
		}
		//clear handlers
		this.eventHandlers[id][eventType] = [];
	},
	registerNative : function(elem, eventType, handler) {
		var id = (elem==window) ? "body" : elem.id;
		var handlers = this.nativeEventHandlers[id];
		if (!handlers) {
			handlers = this.nativeEventHandlers[id] = {};
		}
		if (!handlers[eventType]) {
			handlers[eventType] = [];
		}
		var len = handlers[eventType].length;
		handlers[eventType][len] = handler;
	},
	
//	Use this method to safely attach event handlers to your DOM elements. 
//	VJO will pass a vjo.dsf.Event as the first parameter to your handler 
//	function. The add method returns the bound handler. Save this handler 
// 	in a variable if you later would like to detach the handler. 
//	vjo.dsf.Message's that are returned by the handler will be sent to the 
//	ClientServiceEngine (more about this later).
//  Parameters:
//	id : String - DOM element id
//	eventType : A string representing the event type (i.e. click, mouseover, etc)
//	handler : function - your handler function.
//
//  Returns:
//	Function handler. Use this handler to detach if needed.
 
	add : function(id, eventType, handler, scope) {
		if (!id || !eventType || !handler) {
			return this;
		} 
		var b = this.isBound(id,eventType),
		rv = this.register(id, eventType, handler, scope);
		if (!b) {
			var b = this.bind(id, eventType);
			if (b==null) {
				var len = this.unboundElems.length;
				this.unboundElems[len] = id;		
			}
		}
		return rv;
	},
	
	addEventListener : function(elem,type,listener,scope,capture) {  
		var scp = scope || vjo.global;
		if (typeof elem == 'string') {
			elem = this.ns.Element.get(elem);
		}
		if (!elem) {
			return false;
		}
		var func = function (event) {
			var ev = event || window.event;
			var rv = listener.call(scp,ev,type);
			if (rv===false) {
				vjo.dsf.EventDispatcher.stopEvent(ev);
			}
			if (typeof rv != 'undefined') {
				return rv;
			}
		}
		if (window.addEventListener) {
			elem.addEventListener(type,func,capture||false); 
			this.registerNative(elem,type,func);
			return func;
		} else if (window.attachEvent) {
			elem.attachEvent("on" + type,func); 
			this.registerNative(elem,type,func);
			return func;
		}
		elem["on"+type] = func;
		return false;
	},
	bind : function (id, eventType) {
		var element = this.ns.Element.get(id);
		if (id == "body" || element == document.body) {
			element = document.body;
			if (eventType == "load" || eventType == "unload") {
				var rv = this.addEventListener(window,eventType,
						function (event) {
							var oED = vjo.dsf.EventDispatcher;
							if (typeof oED.fCustomLoad[eventType] == 'function') {
								oED.fCustomLoad[eventType]();
							}
							//oED[eventType]("body");
							//SP
							oED.run(document.body, event || window.event, eventType);
							oED.unregister("body",eventType);
							oED.fCustomLoad = {};
						});
				if (rv===false) {//older browser compatibility
					if (element.vjLoadSet) {
						return this;
					} else {
						element.vjLoadSet = true;
						//store custom onload handlers
						var customLoad = window["on"+eventType] || "";
						if (customLoad) {
							this.fCustomLoad[eventType] = customLoad;
						}
					}
				}
				return this;
			}
		} 
		
		if (element) { //only attach if element exists
			this.addEventListener(element, eventType, this.notifier, element); //pass element so that this works
			return this;
		}
		return null;
	},
	
	
	notifier : function(event, eventType){
		//return vjo.dsf.EventDispatcher[eventType](this, event || window.event);
		//SP
		return vjo.dsf.EventDispatcher.run(this, event || window.event, eventType);
	},
	
	reBind : function () {
		var eH = this.eventHandlers, uE = this.unboundElems, 
		len = uE.length, tmp = [];
		
		for (var i=0; i<len; i++) {
			var id = uE[i], hdls = eH[id];
			if (hdls) {
				for (var type in hdls) {
					if (!this.hasBinding(id,type)) {
						var rv = this.bind(id,type);
						if (rv==null) {
							tmp[tmp.length] = id;
						}
					}
				}
			}
		}
		this.unboundElems = tmp;
	},
	
	isBound : function (id,type) {
		var handlers = this.eventHandlers[id];
		return (handlers && handlers[type] && handlers[type].length>0);
	},
	
	hasBinding : function (id,type) {
		var nEH = this.nativeEventHandlers;
		if (nEH[id] && nEH[id][type]) {
			var aH = nEH[id][type], len = aH.length, rv = false;
			for (var i = 0; i<len; i++) {
				var str = aH[i].toString();
				if (str && str.indexOf('vjo.dsf.EventDispatcher')!=-1) {
					return true;
				}
			}
		}
		return false;
	},
	
//	Parameters
//	elem : a string representing the element that you are removing your handler from.
//	type : a string representing the event type
//	listener : handler
	removeEventListener : function(elem,type,listener) { 
		if (!elem || !type) {
			return;
		} else if (typeof elem == 'string') {
			elem = this.ns.Element.get(elem);
		}
		if (window.addEventListener && listener) {
			elem.removeEventListener(type,listener,false); 
		}
		else if (window.attachEvent && listener) {
			elem.detachEvent("on" + type,listener); 
		}
		else {
			elem["on"+type] = null;
		}
	},
	
	detachNativeHandlers : function (elem,type) {
		var id = (elem==window) ? "body" : elem.id;
		var handlers = this.nativeEventHandlers[id];
		if (handlers && handlers[type]) {
			var h = handlers[type];
			for (var i=0; i<h.length; i++) {
				this.removeEventListener(elem,type,handlers[type][i]);
			}
			handlers[type] = [];
		} 
	},
//
//	Use this method to detach any bound handlers.
// 	Parameters:
//	id : String - DOM element id
//	eventType : A string representing the event type. (i.e. click, mouseover, etc)
//	handler : function
//
	detachHandler : function(id, eventType, handler) {
		var handlers = this.eventHandlers[id];
		if (!handlers || !handlers[eventType]) {
			return;
		}
		var h = [], len = handlers[eventType].length;
		for (var i=0; i<len; i++) {
			if (handler != handlers[eventType][i]) {
				h[h.length] = handlers[eventType][i];
			}
		}
		this.eventHandlers[id][eventType] = h;
		
	},
//
//	Use this method to safely detach event handlers on your DOM elements. 
//	This will remove all handlers of an element, with the given id and event type, 
//	returning nothing.
//  Parameters:
//	id : String - A string of your DOM elemen
//	eventType : A string representing the event type. (i.e. click, mouseover, etc)
//	
	detachHandlers : function(id, eventType) {
		this.unregister(id,eventType);
		var element = this.ns.Element.get(id);
		if (id == "body") {
			element = window;
		} 
		
		if (element) {
			this.detachNativeHandlers(element,eventType);
		}
	},
	stopEvent : function (evt) {
		this.stopPropagation(evt);
		this.preventDefault(evt);
	},
	stopPropagation: function(evt) {
        if (evt.stopPropagation) {
            evt.stopPropagation();
        } else {
            evt.cancelBubble = true;
        }
    },
    preventDefault: function(evt) {
        if (evt.preventDefault) {
            evt.preventDefault();
        } else {
            evt.returnValue = false;
        }
    },
    target : function(event) { 
		return this.resolveTextNode((event.target)?event.target:event.srcElement);
	},
 
	relatedTarget : function(event) { 
		if (event.relatedTarget) return this.resolveTextNode(event.relatedTarget);
		else if ((event.type == "mouseover") && event.fromElement) return this.resolveTextNode(event.fromElement);
		else if ((event.type == "mouseout") && event.toElement) return this.resolveTextNode(event.toElement);
		else return null;		
	},
 
	resolveTextNode : function(node) {
		return (node && (node.nodeType == 3))?node.parentNode:node;
	},
	cleanUp : function () {
		var handlers = this.nativeEventHandlers;
		for (var id in handlers) {
			for (var ev in handlers[id]) {
				if (ev!='unload') {//keep unload handlers
					this.detachHandlers(id,ev,true);	
				}
			}
		}
	},
	getId : function(src, id) {
		var srcId = id;
		if (srcId === null || !srcId) {
			srcId = src.id;
		}
		return srcId;
	},
	
	getBodyId : function(src, id) {
	    var srcId = this.getId(src, id);
	    if (!srcId || src == document.body) {
	        srcId = "body";
	    }
	    return srcId;
	},
	
	/*
	load : function(src, pEvent) {
		var id = this.getBodyId(src);
		var rv = this.process(id, new vjo.dsf.Event(src, 'load', pEvent));
		if (id==='body') { this.unregister('body','load'); };
		return rv;
	},
	*/
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	unload : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'unload', pEvent));
	},
		
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	change : function(src, pEvent) {
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'change', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	submit : function(src, pEvent) {
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'submit', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	reset : function(src, pEvent) { 
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'reset', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	select : function(src, pEvent) { 
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'select', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	blur : function(src, pEvent) { 
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'blur', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	focus : function(src, pEvent) { 
		return this.process(this.getId(src), new vjo.dsf.Event(src, 'focus', pEvent));
	},
	
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	keydown : function(src, pEvent) { 
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'keydown', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	keypress : function(src, pEvent) { 
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'keypress', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	keyup : function(src, pEvent) { 
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'keyup', pEvent));
	},
	
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	click : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'click', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	dblclick : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'dblclick', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	mousedown : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'mousedown', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	mousemove : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'mousemove', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	mouseout : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'mouseout', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	mouseover : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'mouseover', pEvent));
	},
	
	/*
	 * @Deprecated 
	 * Use 'run' method, will be removed a train after Thor rolls out
	 */
	mouseup : function(src, pEvent) {
		return this.process(this.getBodyId(src), new vjo.dsf.Event(src, 'mouseup', pEvent));
	},	
 
	load : function(src, pEvent) {
		return this.run(src, pEvent, 'load');
	},
	
	//SP - Consolidate all event calls into one
	run : function (src, pEvent, eventType) {
		var id = this.getBodyId(src);
		var vEvt = new vjo.dsf.Event(src, eventType, pEvent);
		var rv = this.process(id, vEvt);
		if (eventType==='load' && id==='body') {
			this.unregister('body', 'load'); 
		}
		return rv;
	}
	
})
.inits(function() {
	vjo.dsf.EventDispatcher = new vjo.dsf.EventDispatcher();
	//must cleanup on page unload	
	vjo.dsf.EventDispatcher.addEventListener(window,'load',function(){
		vjo.dsf.EventDispatcher.addEventListener(window,'unload',function(){
			vjo.dsf.EventDispatcher.cleanUp();
		});
	});
})
.endType();
vjo.needs("vjo.dsf.EventDispatcher");
vjo.ctype('vjo.dsf.XDomainRequest')
.protos({
	constructs : function () {
		this.callbacks = [];
		this.sCallbackName = "callback";
		this.sPreId = "xdr_";
		this.sPreExtId = this.sPreId + "ext_";
		this.iCount = 0;
		this.bUseIframe = (navigator.userAgent.indexOf('Firefox')>0);
		vjo.dsf.EventDispatcher.addEventListener(window,"load",this.onLoad,this);
	},
	onLoad : function() {
		this.bodyLoaded = true;
	},
	getReqDiv : function () {
		return document.getElementsByTagName(this.bodyLoaded?"body":"head")[0];
	},
	send : function (poReq) { //returns id of script tag. if you are using this outside of client service engine, you must
		//app must cleanup
		if (!document.createElement || !poReq) {	//not supported
			return;
		}
		var url = "", eid = "";
		if (typeof poReq == "string") {
			url = poReq;
			eid = this.sPreExtId + this.iCount++;
		} else if (poReq.objType=="dsf_Message" && poReq.svcConfig) {
			var cb = this.createCallback(poReq);
			eid = this.sPreId + this.callbacks[this.callbacks.length-1];
			url = poReq.svcConfig.url + "&callback=" + cb;
		}
		var frm = null, doc;
		if (this.bUseIframe) {
			var scriptstr = '<scr' + 'ipt src="'+url+'" type="text/javascript"></scr' + 'ipt>'
			frm  = this.createElement('iframe');
			frm.height = 1;
			frm.width = 1;
			frm.id = eid;
			frm.style.display = 'none';
			this.getReqDiv().appendChild(frm);
			doc = frm.document || frm.contentDocument;
			doc.open();
			doc.write('<html><head></head><body>'+scriptstr+'</body></html>');
			doc.close();
		} else {
			doc = document;
			var scpt = this.createElement("script");
			scpt.id = eid;
			scpt.type = 'text/javascript';
			scpt.src = url;
			this.getReqDiv().appendChild(scpt);
		}
		return eid; //callback should call parent.cb for firefox. parent.cb should be safe regardless
	},
	
	createCallback : function (poMessage) {
		var len = this.callbacks.length, name = this.sCallbackName + len,
		eid = this.sPreId+name;
		this.callbacks[len] = name;
		this[name] = function (poResponse) {
			var resp;
			try {
				resp = poResponse;//JSON.parse(psResponse);
			} catch (e) {
				resp = new vjo.dsf.ServiceResponse();
	   			var error = new vjo.dsf.Error();
	   			error.id = "SYS.JSON_PARSE_ERROR";
	   			error.message = "SYS.JSON_PARSE_ERROR";
	   			resp.errors = [error]
			}
			this.loaded(eid);
			poMessage.response = resp;
			vjo.dsf.ServiceEngine.handleResponse(poMessage);
		}
		//TODO: add scoping
		var rv = "vjo.dsf.XDomainRequest."+name;
		if (this.bUseIframe) {
			rv = "parent." + rv;
		}
		return rv;
	},
	
	loaded : function (psName) {
		var e = document.getElementById(psName);
		if (e != null) e.parentNode.removeChild(e);
	},
	createElement : function (psType) {
		return (typeof(createElementV4)!="undefined")?createElementV4(psType):document.createElement(psType);
	}
})
.inits(function (){
	vjo.dsf.XDomainRequest = new vjo.dsf.XDomainRequest();
})
.endType();
 
vjo.needs("vjo.dsf.XDomainRequest");
vjo.ctype('vjo.dsf.RemoteReqtHdl')
.protos({
	constructs : function () {
		this.reqTimers = {};
		this.timerCount = 0;
		this.processed = {};
	},
	handleRequest : function(message) {
		message.trace = message.trace + '-->RemoteHdl_' + message.svcId;
		if (message.svcConfig) {
			this.invoke(message);	
		}
	},
	
	invoke : function(message) {
		var svc = vjo.dsf.Service, xmlHttpReq = svc.getXmlHttpReq(), requestUrl = message.svcConfig.url,
		cfg = message.svcConfig;
		message.status = -1; //do not handle Response. Ajax call will handle response
	    if (cfg.respMarshalling == 'JSCALLBACK') {
	    	vjo.dsf.XDomainRequest.send(message);
	    	return;
	    }
	    
		try {
			var async = (cfg.async === false) ? false : true;
			xmlHttpReq.open(cfg.method, requestUrl, async);
		}
		catch (e) {
			var resp = new vjo.dsf.ServiceResponse();
			var error = new vjo.dsf.Error();
	   		error.id = "SYS.DARWIN_SERVICE_PROTOCOL_ERROR";
	   		error.message = "SYS.PROTOCOL_ERROR: Cannot open URL '" + requestUrl + "'";
	   		resp.errors = [error]
	   		message.response = resp;
	   		vjo.dsf.ServiceEngine.handleResponse(message);
			return;
		}
		var idx = this.timerCount++;
		this.setupReadyState(xmlHttpReq,message,idx);
	    
	    if (cfg.method == 'POST') {
	    	xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	    	xmlHttpReq.setRequestHeader('Content-Length', message.rawRequest.length);
	    	xmlHttpReq.send(message.rawRequest); 	   	
	    }
	    else {
	    	xmlHttpReq.send(null);
	    }
	    if (cfg.timeout) { //default is 0. do not set timeout, if not defined
	    	var _this = this;
	    	this.reqTimers[idx] = window.setTimeout(function () { _this.timeout(xmlHttpReq,message,idx); },cfg.timeout)
	    }
	    
	},
	setupReadyState : function (xmlHttp,message,idx) {
		var _this = this;
		xmlHttp.onreadystatechange = function() {
	    	if (xmlHttp.readyState != 4) {
				return;
			}
			if (_this.processed[idx]) {//has been processed
				return;
			}
			_this.processed[idx] = true;
			var timer = _this.reqTimers[idx];
			if (timer) {//clear timeout
				window.clearTimeout(timer);
				delete _this.reqTimers[idx];
			}
	    	vjo.dsf.Service.callback(xmlHttp, message);
	    }
	},
	timeout : function (xmlHttp,message,idx) {
		if (this.processed[idx]) {
			return;
		}
		this.processed[idx] = true;
		delete xmlHttp.onreadystatechange;
		xmlHttp.abort();
		delete this.reqTimers[idx];
		var resp = new vjo.dsf.ServiceResponse();
		var error = new vjo.dsf.Error();
   		error.id = "SYS.DARWIN_SERVICE_PROTOCOL_ERROR";
   		error.message = "SYS.PROTOCOL_ERROR: Service timed out.";
   		resp.errors = [error]
   		message.response = resp;
   		vjo.dsf.ServiceEngine.handleResponse(message);
	}
})
.endType();
 
//var svcEngine = new vjo.dsf.ClientServiceEngine();
vjo.ctype('vjo.dsf.ServiceResponse')
.protos({
	constructs : function () {
		this.objType = 'dsf_ServiceResponse';
		this.errors = [];
		this.data = null;
	}
})
.endType();
vjo.needs("vjo.dsf.ServiceResponse");
vjo.ctype('vjo.dsf.InProcReqtHdl')
.protos({
	constructs : function () {
		this.svcHdls = {};
	},
	registerSvcHdl : function(svcId, handler) {
		this.svcHdls[svcId] = handler;
	},
	getSvcHdl : function(svcId) {
		return this.svcHdls[svcId];
	},
	handleRequest : function(message) {
		var handler = this.svcHdls[message.svcId];
		if (handler) {
			// changed to use message rather than message.request
			var response = new vjo.dsf.ServiceResponse();
			response.data = handler.invoke(message);
			message.trace = message.trace + '-->SvcHdl_' + message.svcId;
			if (response) {
				message.response = response;
			}
		}
		if (typeof message.status == 'undefined' || message.status == null) {
			message.status = 1; //back to response chain
		}
	}
})
.endType();
 
 
vjo.ctype('vjo.dsf.Error')
.protos({
	constructs : function (psId,psMessage) {
		this.id = psId;
		this.message = psMessage;
	}
})
.endType();
/*
 *
 * Handling Encoding/Decoding more efficently when switching from ISO to UTF-8 
 * for encoding
 *
 */
vjo.ctype("vjo.dsf.Enc")
.inits(function(){
	if(typeof(vjo.dsf.Enc.unescape)!="undefined"){
		return;
	}
	vjo.dsf.Enc.unescape = window.unescape;
	vjo.dsf.Enc.decodeURI = window.decodeURI;
	vjo.dsf.Enc.decodeURIComponent = window.decodeURIComponent;
	vjo.dsf.Enc.encodeURIComponent = window.encodeURIComponent;
	vjo.dsf.Enc.encodeURI = window.encodeURI;
})
.endType();
 
vjo.needs('vjo.dsf.Error');
vjo.needs('vjo.dsf.ServiceResponse');
vjo.needs('vjo.dsf.Enc');
vjo.ctype('vjo.dsf.Service')
.props({
	callback : function (xmlHttpReq, message) {
		try {
			if (xmlHttpReq.readyState != 4) {
				return;
			}
			
			if (xmlHttpReq.status >= 200 && xmlHttpReq.status < 300 ) {
				var response = xmlHttpReq.responseText;
		    	if (message.svcConfig.respMarshalling == 'JSON') {
		    		try {
		    			//if (response) {
		    			response = eval("("+response+")");
		    			//} 
		    			/*else {
		    				var resp = response;
		    				response = new vjo.dsf.ServiceResponse();
		    				response.data = resp;
		    			}*/
		    		} catch (e) {
		    			//JSON Parse error
		    			//attach to message and send to handler
		    			response = new vjo.dsf.ServiceResponse();
		    			var error = new vjo.dsf.Error();
		    			error.id = "SYS.JSON_PARSE_ERROR";
		    			error.message = "SYS.JSON_PARSE_ERROR";
		    			response.errors = [error];
		    		}
		    	}
		    	else if (message.svcConfig.respMarshalling == 'XML') {
		    		response = xmlHttpReq.responseXML;
		    	}
				message.response = response;
				message.status = 1; //back to response chain		
			} else { //protocol error
				//attach to message and send to handler
				var resp = new vjo.dsf.ServiceResponse();
	   			var error = new vjo.dsf.Error();
	   			error.id = "SYS.DARWIN_SERVICE_PROTOCOL_ERROR";
	   			error.message = "SYS.PROTOCOL_ERROR: status = " + xmlHttpReq.status;
	   			resp.errors = [error]
	   			message.response = resp;
			}
			//vjo.dsf.ServiceEngine.handleResponse(message);
		}
		catch (e) {//app error
			var resp = new vjo.dsf.ServiceResponse();
	   		var error = new vjo.dsf.Error();
	   		error.id = "SYS.DARWIN_SERVICE_PROTOCOL_ERROR";
	   		error.message = "SYS.PROTOCOL_ERROR: unknown ";
	   		resp.errors = [error]
	   		message.response = resp;
		}
		vjo.dsf.ServiceEngine.handleResponse(message);
		delete xmlHttpReq.onreadystatechange;
		xmlHttpReq = null;
	},
	getXmlHttpReq : function () {
		var xmlHtmlReq = false;
		try {
			xmlHtmlReq = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xmlHtmlReq = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				xmlHtmlReq = false;
			}
		}
		if (!xmlHtmlReq && typeof XMLHttpRequest!='undefined') {
			xmlHtmlReq = new XMLHttpRequest();
		}
		return xmlHtmlReq;
	},
	getClientInfo : function () {
	//returns Browser|Version|[Env] used by V4Services
	//use browser util, once vjlib moves to dsf
		if (this.clientInfo) return this.clientInfo;
		var nv = navigator, agt = nv.userAgent.toLowerCase(), i = 0, ver=b="";
		if (agt.indexOf("firefox")!=-1) {
			b = "Firefox";
			i = agt.lastIndexOf("firefox") + 8;
		}
		else if ((/webkit|khtml/).test(agt)) {
			b = "Safari";
			i = agt.lastIndexOf("safari") + 7;
		} else if(typeof(window.opera)!="undefined") {
			b = "Opera";
			i = agt.lastIndexOf("opera") + 6;
		}
		else if (nv.appName == "Netscape") {
			b = "Netscape";
			i = agt.lastIndexOf("/") + 1;
		}
		else if (agt.indexOf("msie")!=-1) {
			b = "IE";
			i = agt.indexOf("msie") + 4;
		}
		if (b) ver = parseInt((b=="Opera")?window.opera.version():agt.substring(i));
		
		this.clientInfo = b+":"+ver+":"
		return this.clientInfo;
	},
	generateReqParams : function(message) {
		var requestParams = 'svcid=' + vjo.dsf.Enc.encodeURIComponent(message.svcId);
		if (message.stok) {
			requestParams += '&stok=' + message.stok; 
		}
		if (message.pId) {
			requestParams += '&pId=' + message.pId;
		}
		if (message.v) {
			requestParams += '&v=' + message.v;
		}
		
		requestParams = requestParams + '&reqttype=' + message.svcConfig.reqtMarshalling;
		requestParams = requestParams + '&resptype=' + message.svcConfig.respMarshalling;
		requestParams = requestParams + '&clientType=' + this.getClientInfo();
		requestParams += '&request=';	
		var request = message.request, reqtmarsh = message.svcConfig.reqtMarshalling;
		if (reqtmarsh == 'JSON') {
	    	requestParams += vjo.dsf.Enc.encodeURIComponent(JSON.stringify(request));
	    } else if (reqtmarsh == 'JSCALLBACK'){
	    	requestParams += vjo.dsf.Enc.encodeURIComponent(JSON.stringify(request));
	    } else if (reqtmarsh == 'XML') {
	    	requestParams += vjo.dsf.Enc.encodeURIComponent(dsf_xmlize(request, "Request"));
	    } else {
	    	requestParams += vjo.dsf.Enc.encodeURIComponent(request);
	    }
	    return requestParams;
	},
	
	xmlize : function (anyObject, objectName, indentSpace) {
	    indentSpace = indentSpace ? indentSpace : '';
	    var s = indentSpace  + '<' + objectName + '>';
	    if (!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 
	        || anyObject instanceof Boolean || anyObject instanceof Date) {
	        s += dsf_escape("" + anyObject);
	    } else{
	        s += "\n";
	        var itemKey = '';
	        var isArrayItem = anyObject instanceof Array;
	        for (var name in anyObject) {
	        	if (isArrayItem && name == '______array') {
	        		continue;
	        	}       	
	            s += this.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");
	        }
	        s += indentSpace;
	    };
	    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
	},
	
	escape : function(sXml) {
	    return sXml.replace(/&/g, "&amp;")
	        .replace(/</g, "&lt;")
	        .replace(/>/g, "&gt;")
	        .replace(/"/g, "&quot;")
	        .replace(/'/g, "&apos;");
	}
})
.endType();
vjo.ctype('vjo.dsf.SvcConfig')
.protos({
	constructs : function (method, url) {
		this.objType = "dsf_SvcConfig";
		this.url = url;
		this.method = method;
		this.reqtMarshalling = 'raw';
		this.respMarshalling = 'raw';
		this.async = true;
		this.timeout = 0;
	}
})
.endType();
// @JsDoNotOptimize
// @JsDoNotLintValidate
// @Package vjo.dsf
if (!this.JSON) {
    JSON = function () {
 
        function f(n) {
            return n < 10 ? '0' + n : n;
        }
 
        Date.prototype.toJSON = function (key) {
 
            return this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z';
        };
 
        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            gap,
            indent,
            meta = {
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                '"' : '\\"',
                '\\': '\\\\'
            },
            rep;
 
 
        function quote(string) {
            escapeable.lastIndex = 0;
            return escapeable.test(string) ?
                '"' + string.replace(escapeable, function (a) {
                    var c = meta[a];
                    if (typeof c === 'string') {
                        return c;
                    }
                    return '\\u' + ('0000' +
                            (+(a.charCodeAt(0))).toString(16)).slice(-4);
                }) + '"' :
                '"' + string + '"';
        }
 
 
        function str(key, holder) {
            var i,
                k,
                v,
                length,
                mind = gap,
                partial,
                value = holder[key];
            if (value && typeof value === 'object' &&
                    typeof value.toJSON === 'function') {
                value = value.toJSON(key);
            }
            if (typeof rep === 'function') {
                value = rep.call(holder, key, value);
            }
            switch (typeof value) {
            case 'string':
                return quote(value);
 
            case 'number':
                return isFinite(value) ? String(value) : 'null';
 
            case 'boolean':
            case 'null':
                return String(value);
            case 'object':
                if (!value) {
                    return 'null';
                }
                gap += indent;
                partial = [];
                if (typeof value.length === 'number' &&
                        !(value.propertyIsEnumerable('length'))) {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' :
                        gap ? '[\n' + gap +
                                partial.join(',\n' + gap) + '\n' +
                                    mind + ']' :
                              '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }
                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = str(k, value, rep);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = str(k, value, rep);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }
                v = partial.length === 0 ? '{}' :
                    gap ? '{\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                            mind + '}' :
                          '{' + partial.join(',') + '}';
                gap = mind;
                return v;
            }
        }
        return {
            stringify: function (value, replacer, space) {
                var i;
                gap = '';
                indent = '';
                if (typeof space === 'number') {
                    for (i = 0; i < space; i += 1) {
                        indent += ' ';
                    }
                } else if (typeof space === 'string') {
                    indent = space;
                }
                rep = replacer;
                if (replacer && typeof replacer !== 'function' &&
                        (typeof replacer !== 'object' ||
                         typeof replacer.length !== 'number')) {
                    throw new Error('JSON.stringify');
                }
                return str('', {'': value});
            },
 
 
            parse: function (text, reviver) {
                var j;
 
                function walk(holder, key) {
                    var k, v, value = holder[key];
                    if (value && typeof value === 'object') {
                        for (k in value) {
                            if (Object.hasOwnProperty.call(value, k)) {
                                v = walk(value, k);
                                if (v !== undefined) {
                                    value[k] = v;
                                } else {
                                    delete value[k];
                                }
                            }
                        }
                    }
                    return reviver.call(holder, key, value);
                }
                cx.lastIndex = 0;
                if (cx.test(text)) {
                    text = text.replace(cx, function (a) {
                        return '\\u' + ('0000' +
                                (+(a.charCodeAt(0))).toString(16)).slice(-4);
                    });
                }
                if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                    j = eval('(' + text + ')');
                    return typeof reviver === 'function' ?
                        walk({'': j}, '') : j;
                }
                throw new SyntaxError('JSON.parse');
            }
        };
    }();
}
vjo.ctype('vjo.util.Map')
.protos({
	constructs : function (psJavaClass) {
		this.javaClass = psJavaClass || 'java.util.HashMap';
		this.map = {};
	},
	get : function (key) {
		return this.map[key];
	},
	put : function (key,value) {
		return this.map[key] = value;
	},
	remove : function (key) {
		var val = this.map[key];
		delete this.map[key];
		return val;
	},
	size : function () {
		var count = 0;
		for (var key in this.map){
			count ++;
		}
		return count;
	}
	//TODO: keys & values, or possibly a foreach that takes a function
})
.endType();

vjo.ctype('vjo.util.List')
.protos({
	constructs : function (psJavaClass) {
		this.javaClass = psJavaClass || 'java.util.ArrayList';
		this.list = [];
	},
	get : function (index) {
		if (this.size()>index) {
			return this.list[index]
		}
		//array out of bounds exception?
		return null;
	},
	add : function (value) {
		return this.list[this.size()] = value;
	},
	
	remove : function (value) {//TODO: by index also?
		var len = this.size(), tmp = this.list, nlist = [], rv = false;
		for (var i=0; i<len; i++) {
			if (!rv && tmp[i]===value) {
				rv = true;
			} else {
				nlist[nlist.length] = tmp[i];
			}
		}
		this.list = nlist;
		return rv;
	},
	size : function () {
		return this.list.length;
	}
	//for all in?
})
.endType();
vjo.needs("vjo.dsf.RemoteReqtHdl");
vjo.needs("vjo.dsf.InProcReqtHdl");
vjo.needs("vjo.dsf.Service");
vjo.needs("vjo.dsf.ServiceResponse");
vjo.needs("vjo.dsf.SvcConfig");
vjo.needs("vjo.dsf.Message");
vjo.needs("vjo.dsf.Json");
vjo.needs("vjo.util.Map");
vjo.needs("vjo.util.List");
 
//	The ServiceEngine passes messages through a configured set of handlers. 
//  Some handlers are specific to a particular service, some global, and 
//	some are transport related. See the Ajax BinDox on how the 
//	ServiceEngine can communicate with the server's service engine
//	via Ajax. On the client, you can use the service engine for custom event listening. 
//	One component can fire an event (broadcast a message) while another can listen 
// (has a handler registered and interested in that type of message) for the event.
 
vjo.ctype('vjo.dsf.ServiceEngine')
.singleton()
.protos({
	STATUS : {
		ABORT : -1,
		JUMP : 1
	},
	constructs : function () {
		this.svcReqtHdls = {};
		this.svcRespHdls = {};
		this.glbReqtHdls = [];
		this.glbRespHdls = [];
		this.trspReqtHdls = {};
		this.trspRespHdls = {};
		this.svcHdls = {};
		this.inProcHdl = new vjo.dsf.InProcReqtHdl();
		this.remoteHdl = new vjo.dsf.RemoteReqtHdl();
		this.registerTrspReqtHdl('Remote', this.remoteTrspHdl);
		this.registerTrspRespHdl('Remote', this.remoteRespTrspHdl);
	},
	handleRequest : function(oMessage) {
		
		var sJumpTo;
		
		if (oMessage.status != this.STATUS.ABORT && typeof sJumpTo == 'undefined') {
			sJumpTo = this.processServiceRequestHandlers(oMessage);
		}	
		if (oMessage.status != this.STATUS.ABORT && typeof sJumpTo == 'undefined') {
			sJumpTo = this.processGlobalRequestHandlers(oMessage);
		}
		if (oMessage.status != this.STATUS.ABORT && typeof sJumpTo == 'undefined') {
			sJumpTo = this.processTransportHandlers(oMessage);
		}	
		//remote requests will handle the response on their own
		if (oMessage.status != this.STATUS.ABORT && (oMessage.trspType!="Remote" || typeof sJumpTo != 'undefined')) {
			this.handleResponse(oMessage, sJumpTo);
		}
		
		return oMessage.returnData;
	},
	
	processServiceRequestHandlers : function(oMessage){
		var sJumpTo;
		var handlers = this.svcReqtHdls[oMessage.svcId];
		if (handlers) {	
			try {
				for (var i = 0; i < handlers.length; i++) {
					oMessage.trace = oMessage.trace + '-->svcReqtHdl_' + i;
					handlers[i].handleRequest(oMessage);			
					if (oMessage.status == this.STATUS.JUMP) {
						sJumpTo = 'SVC';		
						this.genResponseError(oMessage,"SYS.SVC_REQUEST_ERROR","SYS.SVC_REQUEST_ERROR");		
						break;
					}
				}
			} catch (e) {
				sJumpTo = 'SVC';
				this.genResponseError(oMessage,"SYS.SVC_REQUEST_ERROR","SYS.SVC_REQUEST_ERROR");			
			}
		}
		return sJumpTo;
	},
	
	
	processGlobalRequestHandlers : function(oMessage){
		var sJumpTo;
		if (oMessage.status != this.STATUS.JUMP) {
		    try {
				for (var i = 0; i < this.glbReqtHdls.length; i++) {
					oMessage.trace = oMessage.trace + '-->glbReqtHdl_' + i;
					this.glbReqtHdls[i].handleRequest(oMessage);			
					if (oMessage.status == this.STATUS.JUMP) {
						sJumpTo = 'GLB';
						this.genResponseError(oMessage,"SYS.GLOBAL_REQUEST_ERROR","SYS.GLOBAL_REQUEST_ERROR");	
						break;
					}
				}
			} catch (e) {
				sJumpTo = 'GLB';
				this.genResponseError(oMessage,"SYS.GLOBAL_REQUEST_ERROR","SYS.GLOBAL_REQUEST_ERROR");				
			}
		}
		return sJumpTo;
	},
	
	
	processTransportHandlers : function(oMessage){
		var sJumpTo;
		if (oMessage.status != this.STATUS.JUMP && oMessage.trspType) {
			var handlers = this.trspReqtHdls[oMessage.trspType];
			if (handlers) {	
			    try {
					for (var i = 0; i < handlers.length; i++) {
					oMessage.trace = oMessage.trace + '-->trspReqtHdl_' + i;
						handlers[i].handleRequest(oMessage);				
						if (oMessage.status == this.STATUS.JUMP) {
							this.genResponseError(oMessage, "SYS.TRANS_REQUEST_ERROR","SYS.TRANS_REQUEST_ERROR");	
							break;
						}
					}
				} catch (e){
					this.genResponseError(oMessage,"SYS.TRANS_REQUEST_ERROR","SYS.TRANS_REQUEST_ERROR");					
				}
			}
			
			if (oMessage.status!=this.STATUS.JUMP && oMessage.status!=this.STATUS.ABORT) {
				if (oMessage.trspType==="Remote") {
					this.remoteHdl.handleRequest(oMessage);
				} else {
					this.inProcHdl.handleRequest(oMessage);
				}
			}
		}
		return sJumpTo;
	},
		
	handleResponse : function(message, jumpto) {
		
		if (message.trspType && typeof jumpto == "undefined") {
			this.processTransResponseHandlers(message);
		}
		
		if (jumpto != 'SVC') {
			this.processGlobalResponseHandlers(message);
		}
		this.processServiceResponseHandlers(message);
	},
	
	processTransResponseHandlers : function(msg){
		var handlers = this.trspRespHdls[msg.trspType];
		try {
			if (handlers) {	
				for (var i = handlers.length - 1; i >= 0; i--) {
					msg.trace = msg.trace + '-->trspRespHdl_' + i;
					handlers[i].handleResponse(msg);				
				}
		    }
		} catch (e) {
	   		this.genResponseError(msg,"SYS.TRANS_RESPONSE_ERROR","SYS.TRANS_RESPONSE_ERROR");	
		}
	},
 
	processGlobalResponseHandlers : function(msg){
		try {
			for (var i = this.glbRespHdls.length - 1; i >= 0 ; i--) {
				msg.trace = msg.trace + '-->glbRespHdl_' + i;
				this.glbRespHdls[i].handleResponse(msg);
			}
		} catch (e) {		
	   		 this.genResponseError(msg,"SYS.GLOB_RESPONSE_ERROR","SYS.GLOB_RESPONSE_ERROR");	
		}
	},
			
	processServiceResponseHandlers : function(msg){
		var applier;
		if (msg.clientContext) {
			applier = msg.clientContext.svcApplier;
		}
		try {
			if (applier) {
				if (typeof applier.onResponse == 'function') {
					applier.onResponse(msg);
				} else if (typeof applier == 'function') {
					applier(msg);
				}
			}
		} catch (e){
			this.genResponseError(msg,"SYS.SVC_RESPONSE_ERROR","SYS.SVC_RESPONSE_ERROR");	
		}
		var handlers = this.svcRespHdls[msg.svcId];		
		if (handlers) {	
			try {		
				for (var i = handlers.length - 1; i >= 0; i--) {
					msg.trace = msg.trace + '-->svcRespHdl_' + i;	
					handlers[i].handleResponse(msg);		
				}
			} catch (e) {
				this.genResponseError(msg,"SYS.SVC_RESPONSE_ERROR","SYS.SVC_RESPONSE_ERROR");
			}
		}			
	},	
	
	createHandler : function (handler,methodName) {
		if (typeof handler[methodName] != 'function') {
			if (typeof handler == 'function') {
				var func = handler, obj = {}, self = this;
				obj[methodName] = function () {
					return func.apply(self,arguments);
				};
				handler = obj;
			}
		}
		return handler;
	},
//	Parameters:
//  svcId - A string representing service id to associate the handler with.
// 	handler - A function that represents the target service. 
//	This is the pivot point in the diagram above. There can only be one service per service id.
//
	registerSvcHdl : function(svcId, handler) {
		if (!svcId || !handler) {
			return;
		}
		handler = this.createHandler(handler,"invoke");
		this.inProcHdl.registerSvcHdl(svcId, handler);
	},
	getSvcHdl : function (svcId) {
		return this.inProcHdl.getSvcHdl(svcId);
	},
//	svcId - A string representing service id to associate the handler with.
//	handler - A function that represents a service request handler. 
//	These handlers should populate the message with relevent data the 
//	target service will need. There can be multiple service request handlers 
//	for a given service id.
	registerSvcReqtHdl : function(svcId, handler) {
		if (!svcId || !handler) {
			return;
		}
		if (typeof this.svcReqtHdls[svcId] == "undefined") {
			this.svcReqtHdls[svcId] = [];
		}
		var handlers = this.svcReqtHdls[svcId];
		handlers[handlers.length] = this.createHandler(handler,"handleRequest");
	},
//
// Parameters:
//	svcId - A string representing service id to associate the handler with.
//	handler - A function representing a service response handler. 
//	These handlers should be able to use the data provided by the service. 
//	There can be multiple service response handlers for a given service id. 
//	In an Ajax call, these handlers would be equivalent to a callback function. 
//	When the response gets back to the client, these handlers are notified.
	
	registerSvcRespHdl : function(svcId, handler) {
		if (!svcId || !handler) {
			return;
		}
		if (typeof this.svcRespHdls[svcId] == "undefined") {
			this.svcRespHdls[svcId] = [];
		}
		var handlers = this.svcRespHdls[svcId];
		handlers[handlers.length] = this.createHandler(handler,"handleResponse");
	},
//	
// handler : A function that represents a request handler. 
// These handlers will have an opportunity to affect any messages that are 
// sent to the service engine.
//
	registerGlbReqtHdl : function(handler) {
		if (!handler) {
			return;
		}
		this.glbReqtHdls[this.glbReqtHdls.length] = this.createHandler(handler,"handleRequest");
	},
 
// handler - A function that represents a response handler. These handlers will 
// have an oppurtunity to affect any messages that are sent to the service engine.	
	registerGlbRespHdl : function(handler) {
		if (!handler) {
			return;
		}
		this.glbRespHdls[this.glbRespHdls.length] = this.createHandler(handler,"handleResponse");
	},
//	
// 	By default, there are two transport request handlers, "InProc" and "Remote". 
//  For client events, "InProc" is the transport type.
//
	registerTrspReqtHdl : function(transportType, handler) {
		if (!transportType || !handler) {
			return;
		}
		if (typeof this.trspReqtHdls[transportType] == "undefined") {
			this.trspReqtHdls[transportType] = [];
		}
		var handlers = this.trspReqtHdls[transportType];
		handlers[handlers.length] = this.createHandler(handler,"handleRequest");
	},
	registerTrspRespHdl : function(transportType, handler) {
		if (!transportType || !handler) {
			return;
		}
		if (typeof this.trspRespHdls[transportType] == "undefined") {
			this.trspRespHdls[transportType] = [];
		}
		var handlers = this.trspRespHdls[transportType];
		handlers[handlers.length] = this.createHandler(handler,"handleResponse");
	},
	remoteTrspHdl : function (message) {//default v4 remote transport handler
		//NOTE: if there are any "this" references in this method, there may be problems.
		//will need to register with some scope
		var cfg = message.svcConfig;
		if (!cfg || cfg.objType!="dsf_SvcConfig") { //create other svc cfg for existing urls
			return;
		} else if (cfg.respMarshalling == 'JSCALLBACK') {//client assembler
			if (typeof vjo.dsf.assembly != 'undefined' 
				&& typeof vjo.dsf.assembly.VjClientAssembler != 'undefined' 
				&& !vjo.dsf.assembly.VjClientAssembler.bBodyLoaded) {
				vjo.dsf.assembly.VjClientAssembler.load(message);
				message.status = -1;
				return;
			}
		}
		
		if (message.request && message.request.javaClass) {
			delete	message.request.b; //remove this.b from vjo type before serialization
		}
		var svc = vjo.dsf.Service, requestParams = svc.generateReqParams(message), requestUrl = cfg.url;
	    if (message.svcConfig.method == 'GET') {
	    	requestUrl = requestUrl + '?' + requestParams;
	    } else {
	    	message.rawRequest = requestParams;
	    }
	    //if (message.svcConfig.respMarshalling == 'JSCALLBACK') {
	   		//requestUrl += "&callback="+vjo.dsf.XDomainRequest.createCallback(message);
	    //}
	    message.svcConfig.url = requestUrl;
	},
	remoteRespTrspHdl : function (message) {//default v4 remote transport handler
		var resp = message.response;
		if (resp != null && resp.data != null) {
			this.processData(resp.data);
		}
	},
	processData : function (data) {
		this.processObj(data);
		for (var prop in data){
			var o = data[prop];
			if (o!=null && typeof o == 'object') {
				this.processData(o);
			}
		}
	},
	processObj : function (obj) {
		var hint = obj.javaClass;
		if (hint && hint.length>0) {
			if (/java.util.([^\s])*List/.test(hint)) {
				this.addMethods(obj,vjo.util.List.prototype);
			} else if (/java.util.([^\s])*Map/.test(hint)) {
				this.addMethods(obj,vjo.util.Map.prototype);
			}
		}
	},
	addMethods : function (obj,methods) {
		for (var key in methods) {
			obj[key] = methods[key];
		}
	},
	genResponseError : function(msg, errorId, errorMsg) {
	    if (typeof msg.response == 'undefined') {
			var resp = new vjo.dsf.ServiceResponse();
		    	msg.response = resp;
		}	
		var error = new vjo.dsf.Error(errorId,errorMsg);
		msg.response.errors[msg.response.errors.length] = error;	
	},
	
	//Helper method, used with code gen
	register : function (pFuncType, pServiceId, pHandler) {
		var _s = vjo.dsf.ServiceEngine; //DO NOT change it to 'this'
		switch (pFuncType) { 
			case 0:{
				_s.registerSvcHdl(pServiceId, pHandler);
				break;
			} 
			case 1:{
				_s.registerSvcReqtHdl(pServiceId, pHandler);
				break;
			} 
			case 2:{
				_s.registerGlbReqtHdl(pServiceId, pHandler);
				break;
			} 
			case 3:{
				_s.registerTrspReqtHdl(pServiceId, pHandler);
				break;
			} 
			case 4:{
				_s.registerSvcRespHdl(pServiceId, pHandler);
				break;
			} 
			case 5:{
				_s.registerGlbRespHdl(pServiceId, pHandler);
				break;
			} 
			case 6:{
				_s.registerTrspRespHdl(pServiceId, pHandler);
				break;
			}
		}
	}	
	
})
.inits(function () {
		vjo.dsf.ServiceEngine = new vjo.dsf.ServiceEngine();
})
.endType();
 
vjo.ctype("vjo.Registry")
.singleton()
.protos({
	constructs: function () {
		this.controls = [];
	},
	put : function(psKey,poControl){
		this.controls[psKey] = poControl;
		if (this.isKeyValid(psKey)) {//make shorthand reference
			this['_'+psKey] = this.controls[psKey];
		}
		return this.controls[psKey];
	},
 
	get : function(psKey){
		return this.controls[psKey];
	},
	
	dump : function(){
		var controls = this.controls;
		var string = "controls on page:\n";
		for(var i in controls){
			string += "key = " + i;
			string += "controlName = " + controls[i].objtype;
			string +="\n";
		}
		return string;
	},
	isKeyValid : function (psKey) {
		if (typeof psKey != 'string') { return false; };
		return /^([a-zA-Z0-9_$]+)$/.test(psKey);
	}
}).inits( function () {
	vjo.Registry = new vjo.Registry();
})
.endType();