text: var _jsonix_factory = function(_jsonix_xmldom, _jsonix_xmlhttprequest, _jsonix_fs)
  {
  	// Complete Jsonix script is included below 
  var Jsonix = {
  	singleFile : true
  };
  Jsonix.Util = {};
  
  Jsonix.Util.extend = function(destination, source) {
  	destination = destination || {};
  	if (source) {
  		/*jslint forin: true */
  		for ( var property in source) {
  			var value = source[property];
  			if (value !== undefined) {
  				destination[property] = value;
  			}
  		}
  
  		/**
  		 * IE doesn't include the toString property when iterating over an
  		 * object's properties with the for(property in object) syntax.
  		 * Explicitly check if the source has its own toString property.
  		 */
  
  		/*
  		 * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
  		 * prototype object" when calling hawOwnProperty if the source object is
  		 * an instance of window.Event.
  		 */
  
  		// REWORK
  		// Node.js
  		sourceIsEvt = typeof window !== 'undefined' && window !== null && typeof window.Event === "function" && source instanceof window.Event;
  
  		if (!sourceIsEvt && source.hasOwnProperty && source.hasOwnProperty('toString')) {
  			destination.toString = source.toString;
  		}
  	}
  	return destination;
  };
  Jsonix.Class = function() {
  	var Class = function() {
  		this.initialize.apply(this, arguments);
  	};
  	var extended = {};
  	var empty = function() {
  	};
  	var parent, initialize, Type;
  	for (var i = 0, len = arguments.length; i < len; ++i) {
  		Type = arguments[i];
  		if (typeof Type == "function") {
  			// make the class passed as the first argument the superclass
  			if (i === 0 && len > 1) {
  				initialize = Type.prototype.initialize;
  				// replace the initialize method with an empty function,
  				// because we do not want to create a real instance here
  				Type.prototype.initialize = empty;
  				// the line below makes sure that the new class has a
  				// superclass
  				extended = new Type();
  				// restore the original initialize method
  				if (initialize === undefined) {
  					delete Type.prototype.initialize;
  				} else {
  					Type.prototype.initialize = initialize;
  				}
  			}
  			// get the prototype of the superclass
  			parent = Type.prototype;
  		} else {
  			// in this case we're extending with the prototype
  			parent = Type;
  		}
  		Jsonix.Util.extend(extended, parent);
  	}
  	Class.prototype = extended;
  	return Class;
  };
  
  Jsonix.XML = {
  		XMLNS_NS : 'http://www.w3.org/2000/xmlns/',
  		XMLNS_P : 'xmlns'
  };
  
  
  Jsonix.DOM = {
  	isDomImplementationAvailable : function () {
  		if (typeof _jsonix_xmldom !== 'undefined')
  		{
  			return true;
  		} else if (typeof document !== 'undefined' && Jsonix.Util.Type.exists(document.implementation) && Jsonix.Util.Type.isFunction(document.implementation.createDocument)) {
  			return true;
  		} else {
  			return false;
  		}
  	},
  	createDocument : function() {
  		// REWORK
  		// Node.js
  		if (typeof _jsonix_xmldom !== 'undefined')
  		{
  			return new (_jsonix_xmldom.DOMImplementation)().createDocument();
  		} else if (typeof document !== 'undefined' && Jsonix.Util.Type.exists(document.implementation) && Jsonix.Util.Type.isFunction(document.implementation.createDocument)) {
  			return document.implementation.createDocument('', '', null);
  		} else if (typeof ActiveXObject !== 'undefined') {
  			return new ActiveXObject('MSXML2.DOMDocument');
  		} else {
  			throw new Error('Error created the DOM document.');
  		}
  	},
  	serialize : function(node) {
  		Jsonix.Util.Ensure.ensureExists(node);
  		// REWORK
  		// Node.js
  		if (typeof _jsonix_xmldom !== 'undefined')
  		{
  			return (new (_jsonix_xmldom).XMLSerializer()).serializeToString(node);
  		} else if (Jsonix.Util.Type.exists(XMLSerializer)) {
  			return (new XMLSerializer()).serializeToString(node);
  		} else if (Jsonix.Util.Type.exists(node.xml)) {
  			return node.xml;
  		} else {
  			throw new Error('Could not serialize the node, neither XMLSerializer nor the [xml] property were found.');
  		}
  	},
  	parse : function(text) {
  		Jsonix.Util.Ensure.ensureExists(text);
  		if (typeof _jsonix_xmldom !== 'undefined')
  		{
  			return (new (_jsonix_xmldom).DOMParser()).parseFromString(text, 'application/xml');
  		} else if (typeof DOMParser != 'undefined') {
  			return (new DOMParser()).parseFromString(text, 'application/xml');
  		} else if (typeof ActiveXObject != 'undefined') {
  			var doc = Jsonix.DOM.createDocument('', '');
  			doc.loadXML(text);
  			return doc;
  		} else {
  			var url = 'data:text/xml;charset=utf-8,' + encodeURIComponent(text);
  			var request = new XMLHttpRequest();
  			request.open('GET', url, false);
  			if (request.overrideMimeType) {
  				request.overrideMimeType("text/xml");
  			}
  			request.send(null);
  			return request.responseXML;
  		}
  	},
  	load : function(url, callback, options) {
  
  		var request = Jsonix.Request.INSTANCE;
  
  		request.issue(
  						url,
  						function(transport) {
  							var result;
  							if (Jsonix.Util.Type.exists(transport.responseXML) && Jsonix.Util.Type.exists(transport.responseXML.documentElement)) {
  								result = transport.responseXML;
  							} else if (Jsonix.Util.Type.isString(transport.responseText)) {
  								result = Jsonix.DOM.parse(transport.responseText);
  							} else {
  								throw new Error('Response does not have valid [responseXML] or [responseText].');
  							}
  							callback(result);
  
  						}, function(transport) {
  							throw new Error('Could not retrieve XML from URL [' + url	+ '].');
  
  						}, options);
  	},
  	xlinkFixRequired : null,
  	isXlinkFixRequired : function ()
  	{
  		if (Jsonix.DOM.xlinkFixRequired === null)
  		{
  			if (typeof navigator === 'undefined')
  			{
  				Jsonix.DOM.xlinkFixRequired = false;
  			}
  			else if (!!navigator.userAgent && (/Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)))
  			{
  				var doc = Jsonix.DOM.createDocument();
  				var el = doc.createElement('test');
  				el.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'urn:test');
  				doc.appendChild(el);
  				var testString = Jsonix.DOM.serialize(doc);
  				Jsonix.DOM.xlinkFixRequired = (testString.indexOf('xmlns:xlink') === -1);
  			}
  			else
  			{
  				Jsonix.DOM.xlinkFixRequired = false;
  			}
  		}
  		return Jsonix.DOM.xlinkFixRequired;
  	}
  };
  Jsonix.Request = Jsonix
  		.Class({
  			// REWORK
  			factories : [ function() {
  				return new XMLHttpRequest();
  			}, function() {
  				return new ActiveXObject('Msxml2.XMLHTTP');
  			}, function() {
  				return new ActiveXObject("Msxml2.XMLHTTP.6.0");
  			}, function() {
  				return new ActiveXObject("Msxml2.XMLHTTP.3.0");
  			}, function() {
  				return new ActiveXObject('Microsoft.XMLHTTP');
  			}, function() {
  				// Node.js
  				if (typeof _jsonix_xmlhttprequest !== 'undefined')
  				{
  					var XMLHttpRequest = _jsonix_xmlhttprequest.XMLHttpRequest;
  					return new XMLHttpRequest();
  				}
  				else
  				{
  					return null;
  				}
  			}],
  			initialize : function() {
  			},
  			issue : function(url, onSuccess, onFailure, options) {
  				Jsonix.Util.Ensure.ensureString(url);
  				if (Jsonix.Util.Type.exists(onSuccess)) {
  					Jsonix.Util.Ensure.ensureFunction(onSuccess);
  				} else {
  					onSuccess = function() {
  					};
  				}
  				if (Jsonix.Util.Type.exists(onFailure)) {
  					Jsonix.Util.Ensure.ensureFunction(onFailure);
  				} else {
  					onFailure = function() {
  					};
  				}
  				if (Jsonix.Util.Type.exists(options)) {
  					Jsonix.Util.Ensure.ensureObject(options);
  				} else {
  					options = {};
  				}
  
  				var transport = this.createTransport();
  
  				var method = Jsonix.Util.Type.isString(options.method) ? options.method
  						: 'GET';
  				var async = Jsonix.Util.Type.isBoolean(options.async) ? options.async
  						: true;
  				var proxy = Jsonix.Util.Type.isString(options.proxy) ? options.proxy
  						: Jsonix.Request.PROXY;
  
  				var user = Jsonix.Util.Type.isString(options.user) ? options.user
  						: null;
  				var password = Jsonix.Util.Type.isString(options.password) ? options.password
  						: null;
  
  				if (Jsonix.Util.Type.isString(proxy) && (url.indexOf("http") === 0)) {
  					url = proxy + encodeURIComponent(url);
  				}
  
  				if (Jsonix.Util.Type.isString(user)) {
  					transport.open(method, url, async, user, password);
  				} else {
  					transport.open(method, url, async);
  				}
  
  				if (Jsonix.Util.Type.isObject(options.headers)) {
  
  					for ( var header in options.headers) {
  						if (options.headers.hasOwnProperty(header)) {
  							transport.setRequestHeader(header,
  									options.headers[header]);
  						}
  					}
  				}
  
  				var data = Jsonix.Util.Type.exists(options.data) ? options.data
  						: null;
  				if (!async) {
  					transport.send(data);
  					this.handleTransport(transport, onSuccess, onFailure);
  				} else {
  					var that = this;
  					if (typeof window !== 'undefined') {
  
  						transport.onreadystatechange = function() {
  							that.handleTransport(transport, onSuccess,
  									onFailure);
  						};
  
  						window.setTimeout(function() {
  							transport.send(data);
  						}, 0);
  					} else {
  
  						transport.onreadystatechange = function() {
  							that.handleTransport(transport, onSuccess, onFailure);
  						};
  						transport.send(data);
  					}
  				}
  				return transport;
  
  			},
  			handleTransport : function(transport, onSuccess, onFailure) {
  				if (transport.readyState == 4) {
  					if (!transport.status || (transport.status >= 200 && transport.status < 300)) {
  						onSuccess(transport);
  					}
  					if (transport.status && (transport.status < 200 || transport.status >= 300)) {
  						onFailure(transport);
  					}
  				}
  			},
  			createTransport : function() {
  				for ( var index = 0, length = this.factories.length; index < length; index++) {
  					try {
  						var transport = this.factories[index]();
  						if (transport !== null) {
  							return transport;
  						}
  					} catch (e) {
  						// TODO log
  					}
  				}
  				throw new Error('Could not create XML HTTP transport.');
  			},
  			CLASS_NAME : 'Jsonix.Request'
  		});
  Jsonix.Request.INSTANCE = new Jsonix.Request();
  Jsonix.Request.PROXY = null;
  Jsonix.Schema = {};
  Jsonix.Model = {};
  Jsonix.Util.Type = {
  	exists : function(value) {
  		return (typeof value !== 'undefined' && value !== null);
  	},
  	isUndefined : function(value) {
  		return typeof value === 'undefined';
  	},
  	isString : function(value) {
  		return typeof value === 'string';
  	},
  	isBoolean : function(value) {
  		return typeof value === 'boolean';
  	},
  	isObject : function(value) {
  		return typeof value === 'object';
  	},
  	isFunction : function(value) {
  		return typeof value === 'function';
  	},
  	isNumber : function(value) {
  		return (typeof value === 'number') && !isNaN(value);
  	},
  	isNumberOrNaN : function(value) {
  		return (value === +value) || (Object.prototype.toString.call(value) === '[object Number]');
  	},
  	isNaN : function(value) {
  		return Jsonix.Util.Type.isNumberOrNaN(value) && isNaN(value);
  	},
  	isArray : function(value) {
  		// return value instanceof Array;
  		return !!(value && value.concat && value.unshift && !value.callee);
  	},
  	isDate : function(value) {
  		return !!(value && value.getTimezoneOffset && value.setUTCFullYear);
  	},
  	isRegExp : function(value) {
  		return !!(value && value.test && value.exec && (value.ignoreCase || value.ignoreCase === false));
  	},
  	isNode : function(value) {
  		return (typeof Node === "object" || typeof Node === "function") ? (value instanceof Node) : (value && (typeof value === "object") && (typeof value.nodeType === "number") && (typeof value.nodeName==="string"));
  	},
  	isEqual : function(a, b, report) {
  		var doReport = Jsonix.Util.Type.isFunction(report);
  		// TODO rework
  		var _range = function(start, stop, step) {
  			var args = slice.call(arguments);
  			var solo = args.length <= 1;
  			var start_ = solo ? 0 : args[0];
  			var stop_ = solo ? args[0] : args[1];
  			var step_ = args[2] || 1;
  			var len = Math.max(Math.ceil((stop_ - start_) / step_), 0);
  			var idx = 0;
  			var range = new Array(len);
  			while (idx < len) {
  				range[idx++] = start_;
  				start_ += step_;
  			}
  			return range;
  		};
  
  		var _keys = Object.keys || function(obj) {
  			if (Jsonix.Util.Type.isArray(obj)) {
  				return _range(0, obj.length);
  			}
  			var keys = [];
  			for ( var key in obj) {
  				if (obj.hasOwnProperty(key)) {
  					keys[keys.length] = key;
  				}
  			}
  			return keys;
  		};
  
  		// Check object identity.
  		if (a === b) {
  			return true;
  		}
  
  		// Check if both are NaNs
  		if (Jsonix.Util.Type.isNaN(a) && Jsonix.Util.Type.isNaN(b)) {
  			return true;
  		}
  		// Different types?
  		var atype = typeof a;
  		var btype = typeof b;
  		if (atype != btype) {
  			if (doReport) {
  				report('Types differ [' + atype + '], [' + btype + '].');
  			}
  			return false;
  		}
  		// Basic equality test (watch out for coercions).
  		if (a == b) {
  			return true;
  		}
  		// One is falsy and the other truthy.
  		if ((!a && b) || (a && !b)) {
  			if (doReport) {
  				report('One is falsy, the other is truthy.');
  			}
  			return false;
  		}
  		// Check dates' integer values.
  		if (Jsonix.Util.Type.isDate(a) && Jsonix.Util.Type.isDate(b)) {
  			return a.getTime() === b.getTime();
  		}
  		// Both are NaN?
  		if (Jsonix.Util.Type.isNaN(a) && Jsonix.Util.Type.isNaN(b)) {
  			return false;
  		}
  		// Compare regular expressions.
  		if (Jsonix.Util.Type.isRegExp(a) && Jsonix.Util.Type.isRegExp(b)) {
  			return a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline;
  		}
  		
  		if (Jsonix.Util.Type.isNode(a) && Jsonix.Util.Type.isNode(b))
  		{
  			var aSerialized = Jsonix.DOM.serialize(a);
  			var bSerialized = Jsonix.DOM.serialize(b);
  			if (aSerialized !== bSerialized)
  			{
  				if (doReport)
  				{
  					report('Nodes differ.');
  					report('A=' + aSerialized);
  					report('B=' + bSerialized);
  				}
  				return false;
  			}
  			else
  			{
  				return true;
  			}
  		}
  		
  		// If a is not an object by this point, we can't handle it.
  		if (atype !== 'object') {
  			return false;
  		}
  		// Check for different array lengths before comparing contents.
  		if (Jsonix.Util.Type.isArray(a) && (a.length !== b.length)) {
  			if (doReport) {
  					report('Lengths differ.');
  					report('A.length=' + a.length);
  					report('B.length=' + b.length);
  			}
  			return false;
  		}
  		// Nothing else worked, deep compare the contents.
  		var aKeys = _keys(a);
  		var bKeys = _keys(b);
  		// Different object sizes?
  		if (aKeys.length !== bKeys.length) {
  			if (doReport) {
  				report('Different number of properties [' + aKeys.length + '], [' + bKeys.length + '].');
  			}
  			for ( var andex = 0; andex < aKeys.length; andex++) {
  				if (doReport) {
  					report('A [' + aKeys[andex] + ']=' + a[aKeys[andex]]);
  				}
  			}
  			for ( var bndex = 0; bndex < bKeys.length; bndex++) {
  				if (doReport) {
  					report('B [' + bKeys[bndex] + ']=' + b[bKeys[bndex]]);
  				}
  			}
  			return false;
  		}
  		// Recursive comparison of contents.
  		for (var kndex = 0; kndex < aKeys.length; kndex++) {
  			var key = aKeys[kndex];
  			if (!(key in b) || !Jsonix.Util.Type.isEqual(a[key], b[key], report)) {
  				if (doReport) {
  					report('One of the properties differ.');
  					report('Key: [' + key + '].');
  					report('Left: [' + a[key] + '].');
  					report('Right: [' + b[key] + '].');
  				}
  				return false;
  			}
  		}
  		return true;
  	},
  	cloneObject : function (source, target)
  	{
  		target = target || {};
  		for (var p in source)
  		{
  			if (source.hasOwnProperty(p))
  			{
  				target[p] = source[p];
  			}
  		}
  		return target;
  	},
  	defaultValue : function()
  	{
  		var args = arguments;
  		if (args.length === 0)
  		{
  			return undefined;
  		}
  		else
  		{
  			var defaultValue = args[args.length - 1];
  			var typeOfDefaultValue = typeof defaultValue;
  			for (var index = 0; index < args.length - 1; index++)
  			{
  				var candidateValue = args[index];
  				if (typeof candidateValue === typeOfDefaultValue)
  				{
  					return candidateValue;
  				}
  			}
  			return defaultValue;
  			
  		}
  	}
  };
  Jsonix.Util.NumberUtils = {
  	isInteger : function(value) {
  		return Jsonix.Util.Type.isNumber(value) && ((value % 1) === 0);
  	}
  };
  Jsonix.Util.StringUtils = {
  	trim : (!!String.prototype.trim) ?
  	function(str) {
  		Jsonix.Util.Ensure.ensureString(str);
  		return str.trim();
  	} :
  	function(str) {
  		Jsonix.Util.Ensure.ensureString(str);
  		return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  	},
  	/* isEmpty : function(str) {
  		var wcm = Jsonix.Util.StringUtils.whitespaceCharactersMap;
  		for (var index = 0; index < str.length; index++)
  		{
  			if (!wcm[str[index]])
  			{
  				return false;
  			}
  		}
  		return true;
  	}, */
  	isEmpty : function(str) {
  		var length = str.length;
  		if (!length) {
  			return true;
  		}
  		for (var index = 0; index < length; index++)
  		{
  			var c = str[index];
  			if (c === ' ')
  			{
  				// skip
  			}
  			else if (c > '\u000D' && c < '\u0085')
  			{
  				return false;
  			}
  			else if (c < '\u00A0')
  			{
  				if (c < '\u0009')
  				{
  					return false;
  				}
  				else if (c > '\u0085')
  				{
  					return false;
  				}
  			}
  			else if (c > '\u00A0')
  			{
  				if (c < '\u2028')
  				{
  					if (c < '\u180E')
  					{
  						if (c < '\u1680')
  						{
  							return false;
  						}
  						else if(c > '\u1680')
  						{
  							return false;
  						}
  					}
  					else if (c > '\u180E')
  					{
  						if (c < '\u2000')
  						{
  							return false;
  						}
  						else if (c > '\u200A')
  						{
  							return false;
  						}
  					}
  				}
  				else if (c > '\u2029')
  				{
  					if (c < '\u205F')
  					{
  						if (c < '\u202F')
  						{
  							return false;
  						}
  						else if (c > '\u202F')
  						{
  							return false;
  						}
  					}
  					else if (c > '\u205F')
  					{
  						if (c < '\u3000')
  						{
  							return false;
  						}
  						else if (c > '\u3000')
  						{
  							return false;
  						}
  					}
  				}
  			}
  		}
  		return true;
  	},
  	isNotBlank : function(str) {
  		return Jsonix.Util.Type.isString(str) && !Jsonix.Util.StringUtils.isEmpty(str);
  	},
  	whitespaceCharacters: '\u0009\u000A\u000B\u000C\u000D \u0085\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000',
  	whitespaceCharactersMap: {
  		'\u0009' : true,
  		'\u000A' : true,
  		'\u000B' : true,
  		'\u000C' : true,
  		'\u000D' : true,
  		' ' : true,
  		'\u0085' : true,
  		'\u00A0' : true,
  		'\u1680' : true,
  		'\u180E' : true,
  		'\u2000' : true,
  		'\u2001' : true,
  		'\u2002' : true,
  		'\u2003' : true,
  		'\u2004' : true,
  		'\u2005' : true,
  		'\u2006' : true,
  		'\u2007' : true,
  		'\u2008' : true,
  		'\u2009' : true,
  		'\u200A' : true,
  		'\u2028' : true,
  		'\u2029' : true,
  		'\u202F' : true,
  		'\u205F' : true,
  		'\u3000' : true
  	},
  	splitBySeparatorChars : function(str, separatorChars) {
  		Jsonix.Util.Ensure.ensureString(str);
  		Jsonix.Util.Ensure.ensureString(separatorChars);
  		var len = str.length;
  		if (len === 0) {
  			return [];
  		}
  		if (separatorChars.length === 1)
  		{
  			return str.split(separatorChars);
  		}
  		else
  		{
  			var list = [];
  			var sizePlus1 = 1;
  			var i = 0;
  			var start = 0;
  			var match = false;
  			var lastMatch = false;
  			var max = -1;
  			var preserveAllTokens = false;
  			// standard case
  				while (i < len) {
  						if (separatorChars.indexOf(str.charAt(i)) >= 0) {
  								if (match || preserveAllTokens) {
  										lastMatch = true;
  										if (sizePlus1++ == max) {
  												i = len;
  												lastMatch = false;
  										}
  										list.push(str.substring(start, i));
  										match = false;
  								}
  								start = ++i;
  								continue;
  						}
  						lastMatch = false;
  						match = true;
  						i++;
  				}
  				if (match || (preserveAllTokens && lastMatch)) {
  					list.push(str.substring(start, i));
  			}
  			return list;
  		}
  	}
  };
  Jsonix.Util.Ensure = {
  	ensureBoolean : function(value) {
  		if (!Jsonix.Util.Type.isBoolean(value)) {
  			throw new Error('Argument [' + value + '] must be a boolean.');
  		}
  	},
  	ensureString : function(value) {
  		if (!Jsonix.Util.Type.isString(value)) {
  			throw new Error('Argument [' + value + '] must be a string.');
  		}
  	},
  	ensureNumber : function(value) {
  		if (!Jsonix.Util.Type.isNumber(value)) {
  			throw new Error('Argument [' + value + '] must be a number.');
  		}
  	},
  	ensureNumberOrNaN : function(value) {
  		if (!Jsonix.Util.Type.isNumberOrNaN(value)) {
  			throw new Error('Argument [' + value + '] must be a number or NaN.');
  		}
  	},
  	ensureInteger : function(value) {
  		if (!Jsonix.Util.Type.isNumber(value)) {
  			throw new Error('Argument must be an integer, but it is not a number.');
  		} else if (!Jsonix.Util.NumberUtils.isInteger(value)) {
  			throw new Error('Argument [' + value + '] must be an integer.');
  		}
  	},
  	ensureDate : function(value) {
  		if (!(value instanceof Date)) {
  			throw new Error('Argument [' + value + '] must be a date.');
  		}
  	},
  	ensureObject : function(value) {
  		if (!Jsonix.Util.Type.isObject(value)) {
  			throw new Error('Argument [' + value + '] must be an object.');
  		}
  	},
  	ensureArray : function(value) {
  		if (!Jsonix.Util.Type.isArray(value)) {
  			throw new Error('Argument [' + value + '] must be an array.');
  		}
  	},
  	ensureFunction : function(value) {
  		if (!Jsonix.Util.Type.isFunction(value)) {
  			throw new Error('Argument [' + value + '] must be a function.');
  		}
  	},
  	ensureExists : function(value) {
  		if (!Jsonix.Util.Type.exists(value)) {
  			throw new Error('Argument [' + value + '] does not exist.');
  		}
  	}
  };
  Jsonix.XML.QName = Jsonix.Class({
  	key : null,
  	namespaceURI : null,
  	localPart : null,
  	prefix : null,
  	string : null,
  	initialize : function(one, two, three) {
  		var namespaceURI;
  		var localPart;
  		var prefix;
  		var key;
  		var string;
  
  		if (!Jsonix.Util.Type.exists(two)) {
  			namespaceURI = '';
  			localPart = one;
  			prefix = '';
  		} else if (!Jsonix.Util.Type.exists(three)) {
  			namespaceURI = Jsonix.Util.Type.exists(one) ? one : '';
  			localPart = two;
  			var colonPosition = two.indexOf(':');
  			if (colonPosition > 0 && colonPosition < two.length) {
  				prefix = two.substring(0, colonPosition);
  				localPart = two.substring(colonPosition + 1);
  			} else {
  				prefix = '';
  				localPart = two;
  			}
  		} else {
  			namespaceURI = Jsonix.Util.Type.exists(one) ? one : '';
  			localPart = two;
  			prefix = Jsonix.Util.Type.exists(three) ? three : '';
  		}
  		this.namespaceURI = namespaceURI;
  		this.localPart = localPart;
  		this.prefix = prefix;
  
  		this.key = (namespaceURI !== '' ? ('{' + namespaceURI + '}') : '') + localPart;
  		this.string = (namespaceURI !== '' ? ('{' + namespaceURI + '}') : '') + (prefix !== '' ? (prefix + ':') : '') + localPart;
  	},
  	toString : function() {
  		return this.string;
  	},
  	// foo:bar
  	toCanonicalString: function(namespaceContext) {
  		var canonicalPrefix = namespaceContext ? namespaceContext.getPrefix(this.namespaceURI, this.prefix) : this.prefix;
  		return this.prefix + (this.prefix === '' ? '' : ':') + this.localPart;
  	},
  	clone : function() {
  		return new Jsonix.XML.QName(this.namespaceURI, this.localPart, this.prefix);
  	},
  	equals : function(that) {
  		if (!that) {
  			return false;
  		} else {
  			return (this.namespaceURI == that.namespaceURI) && (this.localPart == that.localPart);
  		}
  
  	},
  	CLASS_NAME : "Jsonix.XML.QName"
  });
  Jsonix.XML.QName.fromString = function(qNameAsString, namespaceContext, defaultNamespaceURI) {
  	var leftBracket = qNameAsString.indexOf('{');
  	var rightBracket = qNameAsString.lastIndexOf('}');
  	var namespaceURI;
  	var prefixedName;
  	if ((leftBracket === 0) && (rightBracket > 0) && (rightBracket < qNameAsString.length)) {
  		namespaceURI = qNameAsString.substring(1, rightBracket);
  		prefixedName = qNameAsString.substring(rightBracket + 1);
  	} else {
  		namespaceURI = null;
  		prefixedName = qNameAsString;
  	}
  	var colonPosition = prefixedName.indexOf(':');
  	var prefix;
  	var localPart;
  	if (colonPosition > 0 && colonPosition < prefixedName.length) {
  		prefix = prefixedName.substring(0, colonPosition);
  		localPart = prefixedName.substring(colonPosition + 1);
  	} else {
  		prefix = '';
  		localPart = prefixedName;
  	}
  	// If namespace URI was not set and we have a namespace context, try to find the namespace URI via this context
  	if (namespaceURI === null)
  	{
  		if (prefix === '' && Jsonix.Util.Type.isString(defaultNamespaceURI))
  		{
  			namespaceURI = defaultNamespaceURI;
  		}
  		else if (namespaceContext)
  		{
  			namespaceURI = namespaceContext.getNamespaceURI(prefix);
  		}
  	}
  	// If we don't have a namespace URI, assume '' by default
  	// TODO document the assumption
  	if (!Jsonix.Util.Type.isString(namespaceURI))
  	{
  		namespaceURI = defaultNamespaceURI || '';
  	}
  	return new Jsonix.XML.QName(namespaceURI, localPart, prefix);
  };
  Jsonix.XML.QName.fromObject = function(object) {
  	Jsonix.Util.Ensure.ensureObject(object);
  	if (object instanceof Jsonix.XML.QName || (Jsonix.Util.Type.isString(object.CLASS_NAME) && object.CLASS_NAME === 'Jsonix.XML.QName')) {
  		return object;
  	}
  	var localPart = object.localPart||object.lp||null;
  	Jsonix.Util.Ensure.ensureString(localPart);
  	var namespaceURI = object.namespaceURI||object.ns||'';
  	var prefix = object.prefix||object.p||'';
  	return new Jsonix.XML.QName(namespaceURI, localPart, prefix);
  };
  Jsonix.XML.QName.fromObjectOrString = function(value, namespaceContext, defaultNamespaceURI) {
  	if (Jsonix.Util.Type.isString(value))
  	{
  		return Jsonix.XML.QName.fromString(value, namespaceContext, defaultNamespaceURI);
  	}
  	else
  	{
  		return Jsonix.XML.QName.fromObject(value);
  	}
  };
  Jsonix.XML.QName.key = function(namespaceURI, localPart) {
  	Jsonix.Util.Ensure.ensureString(localPart);
  	if (namespaceURI) {
  		var colonPosition = localPart.indexOf(':');
  		if (colonPosition > 0 && colonPosition < localPart.length) {
  			localName = localPart.substring(colonPosition + 1);
  		} else {
  			localName = localPart;
  		}
  		return '{' + namespaceURI + '}' + localName;
  	} else {
  		return localPart;
  	}
  };
  Jsonix.XML.Calendar = Jsonix.Class({
  	year : NaN,
  	month : NaN,
  	day : NaN,
  	hour : NaN,
  	minute : NaN,
  	second : NaN,
  	fractionalSecond : NaN,
  	timezone : NaN,
  	date : null,
  	initialize : function(data) {
  		Jsonix.Util.Ensure.ensureObject(data);
  		// Year
  		if (Jsonix.Util.Type.exists(data.year)) {
  			Jsonix.Util.Ensure.ensureInteger(data.year);
  			Jsonix.XML.Calendar.validateYear(data.year);
  			this.year = data.year;
  		} else {
  			this.year = NaN;
  		}
  		// Month
  		if (Jsonix.Util.Type.exists(data.month)) {
  			Jsonix.Util.Ensure.ensureInteger(data.month);
  			Jsonix.XML.Calendar.validateMonth(data.month);
  			this.month = data.month;
  		} else {
  			this.month = NaN;
  		}
  		// Day
  		if (Jsonix.Util.Type.exists(data.day)) {
  			Jsonix.Util.Ensure.ensureInteger(data.day);
  			if (Jsonix.Util.NumberUtils.isInteger(data.year) && Jsonix.Util.NumberUtils.isInteger(data.month)) {
  				Jsonix.XML.Calendar.validateYearMonthDay(data.year, data.month, data.day);
  			} else if (Jsonix.Util.NumberUtils.isInteger(data.month)) {
  				Jsonix.XML.Calendar.validateMonthDay(data.month, data.day);
  			} else {
  				Jsonix.XML.Calendar.validateDay(data.day);
  			}
  			this.day = data.day;
  		} else {
  			this.day = NaN;
  		}
  		// Hour
  		if (Jsonix.Util.Type.exists(data.hour)) {
  			Jsonix.Util.Ensure.ensureInteger(data.hour);
  			Jsonix.XML.Calendar.validateHour(data.hour);
  			this.hour = data.hour;
  		} else {
  			this.hour = NaN;
  		}
  		// Minute
  		if (Jsonix.Util.Type.exists(data.minute)) {
  			Jsonix.Util.Ensure.ensureInteger(data.minute);
  			Jsonix.XML.Calendar.validateMinute(data.minute);
  			this.minute = data.minute;
  		} else {
  			this.minute = NaN;
  		}
  		// Second
  		if (Jsonix.Util.Type.exists(data.second)) {
  			Jsonix.Util.Ensure.ensureInteger(data.second);
  			Jsonix.XML.Calendar.validateSecond(data.second);
  			this.second = data.second;
  		} else {
  			this.second = NaN;
  		}
  		// Fractional second
  		if (Jsonix.Util.Type.exists(data.fractionalSecond)) {
  			Jsonix.Util.Ensure.ensureNumber(data.fractionalSecond);
  			Jsonix.XML.Calendar.validateFractionalSecond(data.fractionalSecond);
  			this.fractionalSecond = data.fractionalSecond;
  		} else {
  			this.fractionalSecond = NaN;
  		}
  		// Timezone
  		if (Jsonix.Util.Type.exists(data.timezone)) {
  			if (Jsonix.Util.Type.isNaN(data.timezone)) {
  				this.timezone = NaN;
  			} else {
  				Jsonix.Util.Ensure.ensureInteger(data.timezone);
  				Jsonix.XML.Calendar.validateTimezone(data.timezone);
  				this.timezone = data.timezone;
  			}
  		} else {
  			this.timezone = NaN;
  		}
  
  		var initialDate = new Date(0);
  		initialDate.setUTCFullYear(this.year || 1970);
  		initialDate.setUTCMonth(this.month - 1 || 0);
  		initialDate.setUTCDate(this.day || 1);
  		initialDate.setUTCHours(this.hour || 0);
  		initialDate.setUTCMinutes(this.minute || 0);
  		initialDate.setUTCSeconds(this.second || 0);
  		initialDate.setUTCMilliseconds((this.fractionalSecond || 0) * 1000);
  		var timezoneOffset = -60000 * (this.timezone || 0);
  		this.date = new Date(initialDate.getTime() + timezoneOffset);
  	},
  	CLASS_NAME : "Jsonix.XML.Calendar"
  });
  Jsonix.XML.Calendar.MIN_TIMEZONE = -14 * 60;
  Jsonix.XML.Calendar.MAX_TIMEZONE = 14 * 60;
  Jsonix.XML.Calendar.DAYS_IN_MONTH = [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
  Jsonix.XML.Calendar.fromObject = function(object) {
  	Jsonix.Util.Ensure.ensureObject(object);
  	if (Jsonix.Util.Type.isString(object.CLASS_NAME) && object.CLASS_NAME === 'Jsonix.XML.Calendar') {
  		return object;
  	}
  	return new Jsonix.XML.Calendar(object);
  };
  Jsonix.XML.Calendar.validateYear = function(year) {
  	if (year === 0) {
  		throw new Error('Invalid year [' + year + ']. Year must not be [0].');
  	}
  };
  Jsonix.XML.Calendar.validateMonth = function(month) {
  	if (month < 1 || month > 12) {
  		throw new Error('Invalid month [' + month + ']. Month must be in range [1, 12].');
  	}
  };
  Jsonix.XML.Calendar.validateDay = function(day) {
  	if (day < 1 || day > 31) {
  		throw new Error('Invalid day [' + day + ']. Day must be in range [1, 31].');
  	}
  };
  Jsonix.XML.Calendar.validateMonthDay = function(month, day) {
  	Jsonix.XML.Calendar.validateMonth(month);
  	var maxDaysInMonth = Jsonix.XML.Calendar.DAYS_IN_MONTH[month - 1];
  	if (day < 1 || day > Jsonix.XML.Calendar.DAYS_IN_MONTH[month - 1]) {
  		throw new Error('Invalid day [' + day + ']. Day must be in range [1, ' + maxDaysInMonth + '].');
  	}
  };
  Jsonix.XML.Calendar.validateYearMonthDay = function(year, month, day) {
  	// #93 TODO proper validation of 28/29 02
  	Jsonix.XML.Calendar.validateYear(year);
  	Jsonix.XML.Calendar.validateMonthDay(month, day);
  };
  Jsonix.XML.Calendar.validateHour = function(hour) {
  	if (hour < 0 || hour > 23) {
  		throw new Error('Invalid hour [' + hour + ']. Hour must be in range [0, 23].');
  	}
  };
  Jsonix.XML.Calendar.validateMinute = function(minute) {
  	if (minute < 0 || minute > 59) {
  		throw new Error('Invalid minute [' + minute + ']. Minute must be in range [0, 59].');
  	}
  };
  Jsonix.XML.Calendar.validateSecond = function(second) {
  	if (second < 0 || second > 59) {
  		throw new Error('Invalid second [' + second + ']. Second must be in range [0, 59].');
  	}
  };
  Jsonix.XML.Calendar.validateFractionalSecond = function(fractionalSecond) {
  	if (fractionalSecond < 0 || fractionalSecond > 59) {
  		throw new Error('Invalid fractional second [' + fractionalSecond + ']. Fractional second must be in range [0, 1).');
  	}
  };
  Jsonix.XML.Calendar.validateTimezone = function(timezone) {
  	if (timezone < Jsonix.XML.Calendar.MIN_TIMEZONE || timezone > Jsonix.XML.Calendar.MAX_TIMEZONE) {
  		throw new Error('Invalid timezone [' + timezone + ']. Timezone must not be in range [' + Jsonix.XML.Calendar.MIN_TIMEZONE + ', ' + Jsonix.XML.Calendar.MAX_TIMEZONE + '].');
  	}
  };
  Jsonix.XML.Input = Jsonix.Class({
  	root : null,
  	node : null,
  	attributes : null,
  	eventType : null,
  	pns : null,
  	initialize : function(node) {
  		Jsonix.Util.Ensure.ensureExists(node);
  		this.root = node;
  		var rootPnsItem =
  		{
  			'' : ''
  		};
  		rootPnsItem[Jsonix.XML.XMLNS_P] = Jsonix.XML.XMLNS_NS;
  		this.pns = [rootPnsItem];
  	},
  	hasNext : function() {
  		// No current node, we've not started yet
  		if (this.node === null) {
  			return true;
  		} else if (this.node === this.root) {
  			var nodeType = this.node.nodeType;
  			// Root node is document, last event type is END_DOCUMENT
  			if (nodeType === 9 && this.eventType === 8) {
  				return false;
  			}
  			// Root node is element, last event type is END_ELEMENT
  			else if (nodeType === 1 && this.eventType === 2) {
  				return false;
  			} else {
  				return true;
  			}
  		} else {
  			return true;
  		}
  	},
  	next : function() {
  		if (this.eventType === null) {
  			return this.enter(this.root);
  		}
  		// START_DOCUMENT
  		if (this.eventType === 7) {
  			var documentElement = this.node.documentElement;
  			if (documentElement) {
  				return this.enter(documentElement);
  			} else {
  				return this.leave(this.node);
  			}
  		} else if (this.eventType === 1) {
  			var firstChild = this.node.firstChild;
  			if (firstChild) {
  				return this.enter(firstChild);
  			} else {
  				return this.leave(this.node);
  			}
  		} else if (this.eventType === 2) {
  			var nextSibling = this.node.nextSibling;
  			if (nextSibling) {
  				return this.enter(nextSibling);
  			} else {
  				return this.leave(this.node);
  			}
  		} else {
  			return this.leave(this.node);
  		}
  	},
  	enter : function(node) {
  		var nodeType = node.nodeType;
  		this.node = node;
  		this.attributes = null;
  		// Document node
  		if (nodeType === 1) {
  			// START_ELEMENT
  			this.eventType = 1;
  			this.pushNS(node);
  			return this.eventType;
  		} else if (nodeType === 2) {
  			// ATTRIBUTE
  			this.eventType = 10;
  			return this.eventType;
  		} else if (nodeType === 3) {
  			var nodeValue = node.nodeValue;
  			if (Jsonix.Util.StringUtils.isEmpty(nodeValue)) {
  				// SPACE
  				this.eventType = 6;
  			} else {
  				// CHARACTERS
  				this.eventType = 4;
  			}
  			return this.eventType;
  		} else if (nodeType === 4) {
  			// CDATA
  			this.eventType = 12;
  			return this.eventType;
  		} else if (nodeType === 5) {
  			// ENTITY_REFERENCE_NODE = 5
  			// ENTITY_REFERENCE
  			this.eventType = 9;
  			return this.eventType;
  		} else if (nodeType === 6) {
  			// ENTITY_DECLARATION
  			this.eventType = 15;
  			return this.eventType;
  		} else if (nodeType === 7) {
  			// PROCESSING_INSTRUCTION
  			this.eventType = 3;
  			return this.eventType;
  		} else if (nodeType === 8) {
  			// COMMENT
  			this.eventType = 5;
  			return this.eventType;
  		} else if (nodeType === 9) {
  			// START_DOCUMENT
  			this.eventType = 7;
  			return this.eventType;
  		} else if (nodeType === 10) {
  			// DTD
  			this.eventType = 12;
  			return this.eventType;
  		} else if (nodeType === 12) {
  			// NOTATION_DECLARATION
  			this.eventType = 14;
  			return this.eventType;
  		} else {
  			// DOCUMENT_FRAGMENT_NODE = 11
  			throw new Error("Node type [" + nodeType + '] is not supported.');
  		}
  	},
  	leave : function(node) {
  		if (node.nodeType === 9) {
  			if (this.eventType == 8) {
  				throw new Error("Invalid state.");
  			} else {
  				this.node = node;
  				this.attributes = null;
  				// END_ELEMENT
  				this.eventType = 8;
  				return this.eventType;
  			}
  		} else if (node.nodeType === 1) {
  			if (this.eventType == 2) {
  				var nextSibling = node.nextSibling;
  				if (nextSibling) {
  					return this.enter(nextSibling);
  				}
  			} else {
  				this.node = node;
  				this.attributes = null;
  				// END_ELEMENT
  				this.eventType = 2;
  				this.popNS();
  				return this.eventType;
  			}
  		}
  
  		var nextSibling1 = node.nextSibling;
  		if (nextSibling1) {
  			return this.enter(nextSibling1);
  		} else {
  			var parentNode = node.parentNode;
  			this.node = parentNode;
  			this.attributes = null;
  			if (parentNode.nodeType === 9) {
  				this.eventType = 8;
  			} else {
  				this.eventType = 2;
  			}
  			return this.eventType;
  		}
  	},
  	getName : function() {
  		var node = this.node;
  		if (Jsonix.Util.Type.isString(node.nodeName)) {
  			if (Jsonix.Util.Type.isString(node.namespaceURI)) {
  				return new Jsonix.XML.QName(node.namespaceURI, node.nodeName);
  			} else {
  				return new Jsonix.XML.QName(node.nodeName);
  			}
  		} else {
  			return null;
  		}
  	},
  	getNameKey : function() {
  		var node = this.node;
  		if (Jsonix.Util.Type.isString(node.nodeName)) {
  			return Jsonix.XML.QName.key(node.namespaceURI, node.nodeName);
  		} else {
  			return null;
  		}
  	},
  	getText : function() {
  		return this.node.nodeValue;
  	},
  	nextTag : function() {
  		var et = this.next();
  		// TODO isWhiteSpace
  		while (et === 7 || et === 4 || et === 12 || et === 6 || et === 3 || et === 5) {
  			et = this.next();
  		}
  		if (et !== 1 && et !== 2) {
  			// TODO location
  			throw new Error('Expected start or end tag.');
  		}
  		return et;
  	},
  	skipElement : function() {
  		if (this.eventType !== Jsonix.XML.Input.START_ELEMENT) {
  			throw new Error("Parser must be on START_ELEMENT to skip element.");
  		}
  		var numberOfOpenTags = 1;
  		var et;
  		do {
  			et = this.nextTag();
  		    numberOfOpenTags += (et === Jsonix.XML.Input.START_ELEMENT) ? 1 : -1;
  		  } while (numberOfOpenTags > 0);
  		return et;
  	},	
  	getElementText : function() {
  		if (this.eventType != 1) {
  			throw new Error("Parser must be on START_ELEMENT to read next text.");
  		}
  		var et = this.next();
  		var content = '';
  		while (et !== 2) {
  			if (et === 4 || et === 12 || et === 6 || et === 9) {
  				content = content + this.getText();
  			} else if (et === 3 || et === 5) {
  				// Skip PI or comment
  			} else if (et === 8) {
  				// End document
  				throw new Error("Unexpected end of document when reading element text content.");
  			} else if (et === 1) {
  				// End element
  				// TODO location
  				throw new Error("Element text content may not contain START_ELEMENT.");
  			} else {
  				// TODO location
  				throw new Error("Unexpected event type [" + et + "].");
  			}
  			et = this.next();
  		}
  		return content;
  	},
  	retrieveElement : function () {
  		var element;
  		if (this.eventType === 1) {
  			element = this.node;
  		} else if (this.eventType === 10) {
  			element = this.node.parentNode;
  		} else {
  			throw new Error("Element can only be retrieved for START_ELEMENT or ATTRIBUTE nodes.");
  		}
  		return element;
  	},
  	retrieveAttributes : function () {
  		var attributes;
  		if (this.attributes)
  		{
  			attributes = this.attributes;
  		} else if (this.eventType === 1) {
  			attributes = this.node.attributes;
  			this.attributes = attributes;
  		} else if (this.eventType === 10) {
  			attributes = this.node.parentNode.attributes;
  			this.attributes = attributes;
  		} else {
  			throw new Error("Attributes can only be retrieved for START_ELEMENT or ATTRIBUTE nodes.");
  		}
  		return attributes;
  	},
  	getAttributeCount : function() {
  		var attributes = this.retrieveAttributes();
  		return attributes.length;
  	},
  	getAttributeName : function(index) {
  		var attributes = this.retrieveAttributes();
  		if (index < 0 || index >= attributes.length) {
  			throw new Error("Invalid attribute index [" + index + "].");
  		}
  		var attribute = attributes[index];
  		if (Jsonix.Util.Type.isString(attribute.namespaceURI)) {
  			return new Jsonix.XML.QName(attribute.namespaceURI, attribute.nodeName);
  		} else {
  			return new Jsonix.XML.QName(attribute.nodeName);
  		}
  	},
  	getAttributeNameKey : function(index) {
  		var attributes = this.retrieveAttributes();
  		if (index < 0 || index >= attributes.length) {
  			throw new Error("Invalid attribute index [" + index + "].");
  		}
  		var attribute = attributes[index];
  
  		return Jsonix.XML.QName.key(attribute.namespaceURI, attribute.nodeName);
  	},
  	getAttributeValue : function(index) {
  		var attributes = this.retrieveAttributes();
  		if (index < 0 || index >= attributes.length) {
  			throw new Error("Invalid attribute index [" + index + "].");
  		}
  		var attribute = attributes[index];
  		return attribute.value;
  	},
  	getAttributeValueNS : null,
  	getAttributeValueNSViaElement : function(namespaceURI, localPart) {
  		var element = this.retrieveElement();
  		return element.getAttributeNS(namespaceURI, localPart);
  	},
  	getAttributeValueNSViaAttribute : function(namespaceURI, localPart) {
  		var attributeNode = this.getAttributeNodeNS(namespaceURI, localPart);
  		if (Jsonix.Util.Type.exists(attributeNode)) {
  			return attributeNode.nodeValue;
  		}
  		else
  		{
  			return null;
  		}
  	},
  	getAttributeNodeNS : null,
  	getAttributeNodeNSViaElement : function(namespaceURI, localPart) {
  		var element = this.retrieveElement();
  		return element.getAttributeNodeNS(namespaceURI, localPart);
  	},
  	getAttributeNodeNSViaAttributes : function(namespaceURI, localPart) {
  		var attributeNode = null;
  		var attributes = this.retrieveAttributes();
  		var potentialNode, fullName;
  		for (var i = 0, len = attributes.length; i < len; ++i) {
  			potentialNode = attributes[i];
  			if (potentialNode.namespaceURI === namespaceURI) {
  				fullName = (potentialNode.prefix) ? (potentialNode.prefix + ':' + localPart) : localPart;
  				if (fullName === potentialNode.nodeName) {
  					attributeNode = potentialNode;
  					break;
  				}
  			}
  		}
  		return attributeNode;
  	},
  	getElement : function() {
  		if (this.eventType === 1 || this.eventType === 2) {
  			// Go to the END_ELEMENT
  			this.eventType = 2;
  			return this.node;
  		} else {
  			throw new Error("Parser must be on START_ELEMENT or END_ELEMENT to return current element.");
  		}
  	},
  	pushNS : function (node) {
  		var pindex = this.pns.length - 1;
  		var parentPnsItem = this.pns[pindex];
  		var pnsItem = Jsonix.Util.Type.isObject(parentPnsItem) ? pindex : parentPnsItem;
  		this.pns.push(pnsItem);
  		pindex++;
  		var reference = true;
  		if (node.attributes)
  		{
  			var attributes = node.attributes;
  			var alength = attributes.length;
  			if (alength > 0)
  			{
  				// If given node has attributes
  				for (var aindex = 0; aindex < alength; aindex++)
  				{
  					var attribute = attributes[aindex];
  					var attributeName = attribute.nodeName;
  					var p = null;
  					var ns = null;
  					var isNS = false;
  					if (attributeName === 'xmlns')
  					{
  						p = '';
  						ns = attribute.value;
  						isNS = true;
  					}
  					else if (attributeName.substring(0, 6) === 'xmlns:')
  					{
  						p = attributeName.substring(6);
  						ns = attribute.value;
  						isNS = true;
  					}
  					// Attribute is a namespace declaration
  					if (isNS)
  					{
  						if (reference)
  						{
  							pnsItem = Jsonix.Util.Type.cloneObject(this.pns[pnsItem], {});
  							this.pns[pindex] = pnsItem;
  							reference = false;
  						}
  						pnsItem[p] = ns;
  					}
  				}
  			}
  		}		
  	},
  	popNS : function () {
  		this.pns.pop();
  	},
  	getNamespaceURI : function (p) {
  		var pindex = this.pns.length - 1;
  		var pnsItem = this.pns[pindex];
  		pnsItem = Jsonix.Util.Type.isObject(pnsItem) ? pnsItem : this.pns[pnsItem];
  		return pnsItem[p];
  	},
  	CLASS_NAME : "Jsonix.XML.Input"
  
  });
  
  Jsonix.XML.Input.prototype.getAttributeValueNS = (Jsonix.DOM.isDomImplementationAvailable()) ? Jsonix.XML.Input.prototype.getAttributeValueNSViaElement : Jsonix.XML.Input.prototype.getAttributeValueNSViaAttribute;
  Jsonix.XML.Input.prototype.getAttributeNodeNS = (Jsonix.DOM.isDomImplementationAvailable()) ? Jsonix.XML.Input.prototype.getAttributeNodeNSViaElement : Jsonix.XML.Input.prototype.getAttributeNodeNSViaAttributes;
  
  Jsonix.XML.Input.START_ELEMENT = 1;
  Jsonix.XML.Input.END_ELEMENT = 2;
  Jsonix.XML.Input.PROCESSING_INSTRUCTION = 3;
  Jsonix.XML.Input.CHARACTERS = 4;
  Jsonix.XML.Input.COMMENT = 5;
  Jsonix.XML.Input.SPACE = 6;
  Jsonix.XML.Input.START_DOCUMENT = 7;
  Jsonix.XML.Input.END_DOCUMENT = 8;
  Jsonix.XML.Input.ENTITY_REFERENCE = 9;
  Jsonix.XML.Input.ATTRIBUTE = 10;
  Jsonix.XML.Input.DTD = 11;
  Jsonix.XML.Input.CDATA = 12;
  Jsonix.XML.Input.NAMESPACE = 13;
  Jsonix.XML.Input.NOTATION_DECLARATION = 14;
  Jsonix.XML.Input.ENTITY_DECLARATION = 15;
  
  Jsonix.XML.Output = Jsonix.Class({
  	document : null,
  	documentElement : null,
  	node : null,
  	nodes : null,
  	nsp : null,
  	pns : null,
  	namespacePrefixIndex : 0,
  	xmldom : null,
  	initialize : function(options) {
  		// REWORK
  		if (typeof ActiveXObject !== 'undefined') {
  			this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
  		} else {
  			this.xmldom = null;
  		}
  		this.nodes = [];
  		var rootNspItem =
  		{
  			'' : ''
  		};
  		rootNspItem[Jsonix.XML.XMLNS_NS] = Jsonix.XML.XMLNS_P;
  		if (Jsonix.Util.Type.isObject(options)) {
  			if (Jsonix.Util.Type.isObject(options.namespacePrefixes)) {
  				Jsonix.Util.Type.cloneObject(options.namespacePrefixes, rootNspItem);
  			}
  		}
  		this.nsp = [rootNspItem];
  		var rootPnsItem =
  		{
  			'' : ''
  		};
  		rootPnsItem[Jsonix.XML.XMLNS_P] = Jsonix.XML.XMLNS_NS;
  		this.pns = [rootPnsItem];
  	},
  	destroy : function() {
  		this.xmldom = null;
  	},
  	writeStartDocument : function() {
  		// TODO Check
  		var doc = Jsonix.DOM.createDocument();
  		this.document = doc;
  		return this.push(doc);
  	},
  	writeEndDocument : function() {
  		return this.pop();
  
  	},
  	writeStartElement : function(name) {
  		Jsonix.Util.Ensure.ensureObject(name);
  		var localPart = name.localPart || name.lp || null;
  		Jsonix.Util.Ensure.ensureString(localPart);
  		var ns = name.namespaceURI || name.ns || null;
  		var namespaceURI = Jsonix.Util.Type.isString(ns) ? ns : '';
  
  		var p = name.prefix || name.p;
  		var prefix = this.getPrefix(namespaceURI, p);
  
  		var qualifiedName = (!prefix ? localPart : prefix + ':' + localPart);
  
  		var element;
  		if (Jsonix.Util.Type.isFunction(this.document.createElementNS))	{
  			element = this.document.createElementNS(namespaceURI, qualifiedName);
  		}
  		else if (this.xmldom) {
  			element = this.xmldom.createNode(1, qualifiedName, namespaceURI);
  
  		} else {
  			throw new Error("Could not create an element node.");
  		}
  		this.peek().appendChild(element);
  		this.push(element);
  		this.declareNamespace(namespaceURI, prefix);
  		if (this.documentElement === null)
  		{
  			this.documentElement = element;
  			this.declareNamespaces();
  		}
  		return element;
  	},
  	writeEndElement : function() {
  		return this.pop();
  	},
  	writeCharacters : function(text) {
  		var node;
  		if (Jsonix.Util.Type.isFunction(this.document.createTextNode))	{
  			node = this.document.createTextNode(text);
  		}
  		else if (this.xmldom) {
  			node = this.xmldom.createTextNode(text);
  		} else {
  			throw new Error("Could not create a text node.");
  		}
  		this.peek().appendChild(node);
  		return node;
  
  	},
  	writeCdata : function(text) {
  		var node;
  		if (Jsonix.Util.Type.isFunction(this.document.createCDATASection))	{
  			node = this.document.createCDATASection(text);
  		}
  		else if (this.xmldom) {
  			node = this.xmldom.createCDATASection(text);
  		} else {
  			throw new Error("Could not create a CDATA section node.");
  		}
  		this.peek().appendChild(node);
  		return node;
  	},
  	writeAttribute : function(name, value) {
  		Jsonix.Util.Ensure.ensureString(value);
  		Jsonix.Util.Ensure.ensureObject(name);
  		var localPart = name.localPart || name.lp || null;
  		Jsonix.Util.Ensure.ensureString(localPart);
  		var ns = name.namespaceURI || name.ns || null;
  		var namespaceURI = Jsonix.Util.Type.isString(ns) ? ns : '';
  		var p = name.prefix || name.p || null;
  		var prefix = this.getPrefix(namespaceURI, p);
  
  		var qualifiedName = (!prefix ? localPart : prefix + ':' + localPart);
  
  		var node = this.peek();
  
  		if (namespaceURI === '') {
  			node.setAttribute(qualifiedName, value);
  		} else {
  			if (node.setAttributeNS) {
  				node.setAttributeNS(namespaceURI, qualifiedName, value);
  			} else {
  				if (this.xmldom) {
  					var attribute = this.document.createNode(2, qualifiedName, namespaceURI);
  					attribute.nodeValue = value;
  					node.setAttributeNode(attribute);
  				}
  				else if (namespaceURI === Jsonix.XML.XMLNS_NS)
  				{
  					// XMLNS namespace may be processed unqualified
  					node.setAttribute(qualifiedName, value);
  				}
  				else
  				{
  					throw new Error("The [setAttributeNS] method is not implemented");
  				}
  			}
  			this.declareNamespace(namespaceURI, prefix);
  		}
  
  	},
  	writeNode : function(node) {
  		var importedNode;
  		if (Jsonix.Util.Type.exists(this.document.importNode)) {
  			importedNode = this.document.importNode(node, true);
  		} else {
  			importedNode = node;
  		}
  		this.peek().appendChild(importedNode);
  		return importedNode;
  	},
  	push : function(node) {
  		this.nodes.push(node);
  		this.pushNS();
  		return node;
  	},
  	peek : function() {
  		return this.nodes[this.nodes.length - 1];
  	},
  	pop : function() {
  		this.popNS();
  		var result = this.nodes.pop();
  		return result;
  	},
  	pushNS : function ()
  	{
  		var nindex = this.nsp.length - 1;
  		var pindex = this.pns.length - 1;
  		var parentNspItem = this.nsp[nindex];
  		var parentPnsItem = this.pns[pindex];
  		var nspItem = Jsonix.Util.Type.isObject(parentNspItem) ? nindex : parentNspItem;
  		var pnsItem = Jsonix.Util.Type.isObject(parentPnsItem) ? pindex : parentPnsItem;
  		this.nsp.push(nspItem);
  		this.pns.push(pnsItem);
  	},
  	popNS : function ()
  	{
  		this.nsp.pop();
  		this.pns.pop();
  	},
  	declareNamespaces : function ()
  	{
  		var index = this.nsp.length - 1;
  		var nspItem = this.nsp[index];
  		nspItem = Jsonix.Util.Type.isNumber(nspItem) ? this.nsp[nspItem] : nspItem;
  		var ns, p;
  		for (ns in nspItem)
  		{
  			if (nspItem.hasOwnProperty(ns))
  			{
  				p = nspItem[ns];
  				this.declareNamespace(ns, p);
  			}
  		}
  	},
  	declareNamespace : function (ns, p)
  	{
  		var index = this.pns.length - 1;
  		var pnsItem = this.pns[index];
  		var reference;
  		if (Jsonix.Util.Type.isNumber(pnsItem))
  		{
  			// Resolve the reference
  			reference = true;
  			pnsItem = this.pns[pnsItem];
  		}
  		else
  		{
  			reference = false;
  		}
  		// If this prefix is mapped to a different namespace and must be redeclared
  		if (pnsItem[p] !== ns)
  		{
  			if (p === '')
  			{
  				this.writeAttribute({lp : Jsonix.XML.XMLNS_P}, ns);
  			}
  			else
  			{
  				this.writeAttribute({ns : Jsonix.XML.XMLNS_NS, lp : p, p : Jsonix.XML.XMLNS_P}, ns);
  			}
  			if (reference)
  			{
  				// If this was a reference, clone it and replace the reference
  				pnsItem = Jsonix.Util.Type.cloneObject(pnsItem, {});
  				this.pns[index] = pnsItem;
  			}
  			pnsItem[p] = ns;
  		}
  	},
  	getPrefix : function (ns, p)
  	{
  		var index = this.nsp.length - 1;
  		var nspItem = this.nsp[index];
  		var reference;
  		if (Jsonix.Util.Type.isNumber(nspItem))
  		{
  			// This is a reference, the item is the index of the parent item
  			reference = true;
  			nspItem = this.nsp[nspItem];
  		}
  		else
  		{
  			reference = false;
  		}
  		if (Jsonix.Util.Type.isString(p))
  		{
  			var oldp = nspItem[ns];
  			// If prefix is already declared and equals the proposed prefix
  			if (p === oldp)
  			{
  				// Nothing to do
  			}
  			else
  			{
  				// If this was a reference, we have to clone it now
  				if (reference)
  				{
  					nspItem = Jsonix.Util.Type.cloneObject(nspItem, {});
  					this.nsp[index] = nspItem;
  				}
  				nspItem[ns] = p;
  			}
  		}
  		else
  		{
  			p = nspItem[ns];
  			if (!Jsonix.Util.Type.exists(p)) {
  				p = 'p' + (this.namespacePrefixIndex++);
  				// If this was a reference, we have to clone it now
  				if (reference)
  				{
  					nspItem = Jsonix.Util.Type.cloneObject(nspItem, {});
  					this.nsp[index] = nspItem;
  				}
  				nspItem[ns] = p;
  			}
  		}
  		return p;
  	},
  	getNamespaceURI : function (p) {
  		var pindex = this.pns.length - 1;
  		var pnsItem = this.pns[pindex];
  		pnsItem = Jsonix.Util.Type.isObject(pnsItem) ? pnsItem : this.pns[pnsItem];
  		return pnsItem[p];
  	},
  	CLASS_NAME : "Jsonix.XML.Output"
  });
  
  Jsonix.Mapping = {};
  Jsonix.Mapping.Style = Jsonix.Class({
  	marshaller : null,
  	unmarshaller : null,
  	module : null,
  	elementInfo : null,
  	classInfo : null,
  	enumLeafInfo : null,
  	anyAttributePropertyInfo : null,
  	anyElementPropertyInfo : null,
  	attributePropertyInfo : null,
  	elementMapPropertyInfo : null,
  	elementPropertyInfo : null,
  	elementsPropertyInfo : null,
  	elementRefPropertyInfo : null,
  	elementRefsPropertyInfo : null,
  	valuePropertyInfo : null,
  	initialize : function() {
  	},
  	CLASS_NAME : 'Jsonix.Mapping.Style'
  });
  
  Jsonix.Mapping.Style.STYLES = {};
  Jsonix.Mapping.Styled = Jsonix.Class({
  	mappingStyle : null,
  	initialize : function(options) {
  		if (Jsonix.Util.Type.exists(options)) {
  			Jsonix.Util.Ensure.ensureObject(options);
  			if (Jsonix.Util.Type.isString(options.mappingStyle)) {
  				var mappingStyle = Jsonix.Mapping.Style.STYLES[options.mappingStyle];
  				if (!mappingStyle) {
  					throw new Error("Mapping style [" + options.mappingStyle + "] is not known.");
  				}
  				this.mappingStyle = mappingStyle;
  			} else if (Jsonix.Util.Type.isObject(options.mappingStyle)) {
  				this.mappingStyle = options.mappingStyle;
  			}
  		}
  		if (!this.mappingStyle) {
  			this.mappingStyle = Jsonix.Mapping.Style.STYLES.standard;
  		}
  	},
  	CLASS_NAME : 'Jsonix.Mapping.Styled'
  });
  Jsonix.Binding = {};
  Jsonix.Binding.Marshalls = {
  };
  
  Jsonix.Binding.Marshalls.Element = Jsonix.Class({
  	marshalElement : function(value, context, output, scope) {
  		var elementValue = this.convertToTypedNamedValue(value, context, output, scope);
  		var declaredTypeInfo = elementValue.typeInfo;
  		var actualTypeInfo = undefined;
  		if (context.supportXsiType && Jsonix.Util.Type.exists(elementValue.value))
  		{
  			var typeInfoByValue = context.getTypeInfoByValue(elementValue.value);
  			if (typeInfoByValue && typeInfoByValue.typeName)
  			{
  				actualTypeInfo = typeInfoByValue;
  			}
  		}
  		var typeInfo = actualTypeInfo || declaredTypeInfo;
  
  		if (typeInfo) {
  			output.writeStartElement(elementValue.name);
  			if (actualTypeInfo && declaredTypeInfo !== actualTypeInfo) {
  				var xsiTypeName = actualTypeInfo.typeName;
  				var xsiType = Jsonix.Schema.XSD.QName.INSTANCE.print(xsiTypeName, context, output, scope);
  				output.writeAttribute(Jsonix.Schema.XSI.TYPE_QNAME, xsiType);
  			}
  			if (Jsonix.Util.Type.exists(elementValue.value)) {
  				typeInfo.marshal(elementValue.value, context, output, scope);
  			}
  			output.writeEndElement();
  		} else {
  			throw new Error("Element [" + elementValue.name.key + "] is not known in this context, could not determine its type.");
  		}
  	},
  	getTypeInfoByElementName : function(name, context, scope) {
  		var elementInfo = context.getElementInfo(name, scope);
  		if (Jsonix.Util.Type.exists(elementInfo)) {
  			return elementInfo.typeInfo;
  		} else {
  			return undefined;
  		}
  	}
  });
  Jsonix.Binding.Marshalls.Element.AsElementRef = Jsonix.Class({
  	convertToTypedNamedValue : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var elementValue = this.convertToNamedValue(value, context, output, scope);
  		return {
  			name : elementValue.name,
  			value : elementValue.value,
  			typeInfo : this.getTypeInfoByElementName(elementValue.name, context, scope)
  		};
  	},
  	convertToNamedValue : function(elementValue, context, output, scope) {
  		var name;
  		var value;
  		if (Jsonix.Util.Type.exists(elementValue.name) && !Jsonix.Util.Type.isUndefined(elementValue.value)) {
  			name = Jsonix.XML.QName.fromObjectOrString(elementValue.name, context);
  			value = Jsonix.Util.Type.exists(elementValue.value) ? elementValue.value : null;
  			return {
  				name : name,
  				value : value
  			};
  		} else {
  			for ( var propertyName in elementValue) {
  				if (elementValue.hasOwnProperty(propertyName)) {
  					name = Jsonix.XML.QName.fromObjectOrString(propertyName, context);
  					value = elementValue[propertyName];
  					return {
  						name : name,
  						value : value
  					};
  				}
  			}
  		}
  		throw new Error("Invalid element value [" + elementValue + "]. Element values must either have {name:'myElementName', value: elementValue} or {myElementName:elementValue} structure.");
  	}
  });
  
  Jsonix.Binding.Unmarshalls = {};
  
  Jsonix.Binding.Unmarshalls.WrapperElement = Jsonix.Class({
  	mixed : false,
  	unmarshalWrapperElement : function(context, input, scope, callback) {
  		var et = input.next();
  		while (et !== Jsonix.XML.Input.END_ELEMENT) {
  			if (et === Jsonix.XML.Input.START_ELEMENT) {
  				this.unmarshalElement(context, input, scope, callback);
  			} else
  			// Characters
  			if (this.mixed && (et === Jsonix.XML.Input.CHARACTERS || et === Jsonix.XML.Input.CDATA || et === Jsonix.XML.Input.ENTITY_REFERENCE)) {
  				callback(input.getText());
  			} else if (et === Jsonix.XML.Input.SPACE || et === Jsonix.XML.Input.COMMENT || et === Jsonix.XML.Input.PROCESSING_INSTRUCTION) {
  				// Skip whitespace
  			} else {
  				throw new Error("Illegal state: unexpected event type [" + et + "].");
  			}
  			et = input.next();
  		}
  	}
  });
  
  Jsonix.Binding.Unmarshalls.Element = Jsonix.Class({
  	allowTypedObject : true,
  	allowDom : false,
  	unmarshalElement : function(context, input, scope, callback) {
  		if (input.eventType != 1) {
  			throw new Error("Parser must be on START_ELEMENT to read next element.");
  		}
  		var typeInfo = this.getTypeInfoByInputElement(context, input, scope);
  		var name = input.getName();
  		var elementValue;
  		if (this.allowTypedObject) {
  			if (Jsonix.Util.Type.exists(typeInfo)) {
  				var value = typeInfo.unmarshal(context, input, scope);
  				var typedNamedValue = {
  					name : name,
  					value : value,
  					typeInfo : typeInfo
  				};
  				elementValue = this.convertFromTypedNamedValue(typedNamedValue, context, input, scope);
  			} else if (this.allowDom) {
  				elementValue = input.getElement();
  			} else {
  				throw new Error("Element [" + name.toString() + "] could not be unmarshalled as is not known in this context and the property does not allow DOM content.");
  			}
  		} else if (this.allowDom) {
  			elementValue = input.getElement();
  		} else {
  			throw new Error("Element [" + name.toString() + "] could not be unmarshalled as the property neither allows typed objects nor DOM as content. This is a sign of invalid mappings, do not use [allowTypedObject : false] and [allowDom : false] at the same time.");
  		}
  		callback(elementValue);
  	},
  	getTypeInfoByInputElement : function(context, input, scope) {
  		var xsiTypeInfo = null;
  		if (context.supportXsiType) {
  			var xsiType = input.getAttributeValueNS(Jsonix.Schema.XSI.NAMESPACE_URI, Jsonix.Schema.XSI.TYPE);
  			if (Jsonix.Util.StringUtils.isNotBlank(xsiType)) {
  				var xsiTypeName = Jsonix.Schema.XSD.QName.INSTANCE.parse(xsiType, context, input, scope);
  				xsiTypeInfo = context.getTypeInfoByTypeNameKey(xsiTypeName.key);
  			}
  		}
  		var name = input.getName();
  		var typeInfo = xsiTypeInfo ? xsiTypeInfo : this.getTypeInfoByElementName(name, context, scope);
  		return typeInfo;
  	},
  	getTypeInfoByElementName : function(name, context, scope) {
  		var elementInfo = context.getElementInfo(name, scope);
  		if (Jsonix.Util.Type.exists(elementInfo)) {
  			return elementInfo.typeInfo;
  		} else {
  			return undefined;
  		}
  	}
  });
  
  Jsonix.Binding.Unmarshalls.Element.AsElementRef = Jsonix.Class({
  	convertFromTypedNamedValue : function(typedNamedValue, context, input, scope) {
  		return {
  			name : typedNamedValue.name,
  			value : typedNamedValue.value
  		};
  	}
  });
  
  Jsonix.Binding.Unmarshalls.Element.AsSimplifiedElementRef = Jsonix.Class({
  	convertFromTypedNamedValue : function(typedNamedValue, context, input, scope) {
  		var propertyName = typedNamedValue.name.toCanonicalString(context);
  		var value = {};
  		value[propertyName] = typedNamedValue.value;
  		return value;
  	}
  });
  Jsonix.Binding.Marshaller = Jsonix.Class(Jsonix.Binding.Marshalls.Element, Jsonix.Binding.Marshalls.Element.AsElementRef, {
  	context : null,
  	initialize : function(context) {
  		Jsonix.Util.Ensure.ensureObject(context);
  		this.context = context;
  	},
  	marshalString : function(value) {
  		var doc = this.marshalDocument(value);
  		var text = Jsonix.DOM.serialize(doc);
  		return text;
  	},
  	marshalDocument : function(value) {
  		var output = new Jsonix.XML.Output({
  			namespacePrefixes : this.context.namespacePrefixes
  		});
  
  		var doc = output.writeStartDocument();
  		this.marshalElement(value, this.context, output, undefined);
  		output.writeEndDocument();
  		return doc;
  	},
  	CLASS_NAME : 'Jsonix.Binding.Marshaller'
  });
  Jsonix.Binding.Marshaller.Simplified = Jsonix.Class(Jsonix.Binding.Marshaller, {
  	CLASS_NAME : 'Jsonix.Binding.Marshaller.Simplified'
  });
  Jsonix.Binding.Unmarshaller = Jsonix.Class(Jsonix.Binding.Unmarshalls.Element, Jsonix.Binding.Unmarshalls.Element.AsElementRef, {
  	context : null,
  	allowTypedObject : true,
  	allowDom : false,
  	initialize : function(context) {
  		Jsonix.Util.Ensure.ensureObject(context);
  		this.context = context;
  	},
  	unmarshalString : function(text) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var doc = Jsonix.DOM.parse(text);
  		return this.unmarshalDocument(doc);
  	},
  	unmarshalURL : function(url, callback, options) {
  		Jsonix.Util.Ensure.ensureString(url);
  		Jsonix.Util.Ensure.ensureFunction(callback);
  		if (Jsonix.Util.Type.exists(options)) {
  			Jsonix.Util.Ensure.ensureObject(options);
  		}
  		that = this;
  		Jsonix.DOM.load(url, function(doc) {
  			callback(that.unmarshalDocument(doc));
  		}, options);
  	},
  	unmarshalFile : function(fileName, callback, options) {
  		if (typeof _jsonix_fs === 'undefined') {
  			throw new Error("File unmarshalling is only available in environments which support file systems.");
  		}
  		Jsonix.Util.Ensure.ensureString(fileName);
  		Jsonix.Util.Ensure.ensureFunction(callback);
  		if (Jsonix.Util.Type.exists(options)) {
  			Jsonix.Util.Ensure.ensureObject(options);
  		}
  		that = this;
  		var fs = _jsonix_fs;
  		fs.readFile(fileName, options, function(err, data) {
  			if (err) {
  				throw err;
  			} else {
  				var text = data.toString();
  				var doc = Jsonix.DOM.parse(text);
  				callback(that.unmarshalDocument(doc));
  			}
  		});
  	},
  	unmarshalDocument : function(doc, scope) {
  		var input = new Jsonix.XML.Input(doc);
  		var result = null;
  		var callback = function(_result) {
  			result = _result;
  		};
  		input.nextTag();
  		this.unmarshalElement(this.context, input, scope, callback);
  		return result;
  
  	},
  	CLASS_NAME : 'Jsonix.Binding.Unmarshaller'
  });
  Jsonix.Binding.Unmarshaller.Simplified = Jsonix.Class(Jsonix.Binding.Unmarshaller, Jsonix.Binding.Unmarshalls.Element.AsSimplifiedElementRef, {
  	CLASS_NAME : 'Jsonix.Binding.Unmarshaller.Simplified'
  });
  Jsonix.Model.TypeInfo = Jsonix.Class({
  	module: null,			
  	name : null,
  	baseTypeInfo : null,
  	initialize : function() {
  	},
  	isBasedOn : function(typeInfo) {
  		var currentTypeInfo = this;
  		while (currentTypeInfo) {
  			if (typeInfo === currentTypeInfo) {
  				return true;
  			}
  			currentTypeInfo = currentTypeInfo.baseTypeInfo;
  		}
  		return false;
  	},
  	CLASS_NAME : 'Jsonix.Model.TypeInfo'
  });
  Jsonix.Model.ClassInfo = Jsonix
  		.Class(Jsonix.Model.TypeInfo, Jsonix.Mapping.Styled, {
  			name : null,
  			localName : null,
  			typeName : null,
  			instanceFactory : null,
  			properties : null,
  			propertiesMap : null,
  			structure : null,
  			targetNamespace : '',
  			defaultElementNamespaceURI : '',
  			defaultAttributeNamespaceURI : '',
  			built : false,
  			initialize : function(mapping, options) {
  				Jsonix.Model.TypeInfo.prototype.initialize.apply(this, []);
  				Jsonix.Mapping.Styled.prototype.initialize.apply(this, [options]);
  				Jsonix.Util.Ensure.ensureObject(mapping);
  				var n = mapping.name||mapping.n||undefined;
  				Jsonix.Util.Ensure.ensureString(n);
  				this.name = n;
  
  				var ln = mapping.localName||mapping.ln||null;
  				this.localName = ln;
  
  				var dens = mapping.defaultElementNamespaceURI||mapping.dens||mapping.targetNamespace||mapping.tns||'';
  				this.defaultElementNamespaceURI = dens;
  
  				var tns =  mapping.targetNamespace||mapping.tns||mapping.defaultElementNamespaceURI||mapping.dens||this.defaultElementNamespaceURI;
  				this.targetNamespace = tns;
  
  				var dans = mapping.defaultAttributeNamespaceURI||mapping.dans||'';
  				this.defaultAttributeNamespaceURI = dans;
  
  				var bti = mapping.baseTypeInfo||mapping.bti||null;
  				this.baseTypeInfo = bti;
  
  				var inF = mapping.instanceFactory||mapping.inF||undefined;
  				if (Jsonix.Util.Type.exists(inF)) {
  					// TODO: should we support instanceFactory as functions?
  					// For the pure JSON configuration?
  					Jsonix.Util.Ensure.ensureFunction(inF);
  					this.instanceFactory = inF;
  				}
  
  				var tn = mapping.typeName||mapping.tn||undefined;
  
  				if (Jsonix.Util.Type.exists(tn))
  				{
  					if (Jsonix.Util.Type.isString(tn))
  					{
  						this.typeName = new Jsonix.XML.QName(this.targetNamespace, tn);
  					}
  					else {
  						this.typeName = Jsonix.XML.QName.fromObject(tn);
  					}
  				}
  				else if (Jsonix.Util.Type.exists(ln))
  				{
  					this.typeName = new Jsonix.XML.QName(tns, ln);
  				}
  
  				this.properties = [];
  				this.propertiesMap = {};
  				var ps = mapping.propertyInfos||mapping.ps||[];
  				Jsonix.Util.Ensure.ensureArray(ps);
  				for ( var index = 0; index < ps.length; index++) {
  					this.p(ps[index]);
  				}
  			},
  			getPropertyInfoByName : function(name) {
  				return this.propertiesMap[name];
  			},
  			// Obsolete
  			destroy : function() {
  			},
  			build : function(context) {
  				if (!this.built) {
  					this.baseTypeInfo = context.resolveTypeInfo(this.baseTypeInfo, this.module);
  					if (Jsonix.Util.Type.exists(this.baseTypeInfo)) {
  						this.baseTypeInfo.build(context);
  					}
  
  					// Build properties in this context
  					for ( var index = 0; index < this.properties.length; index++) {
  						var propertyInfo = this.properties[index];
  						propertyInfo.build(context, this.module);
  					}
  
  					// Build the structure
  					var structure = {
  						elements : null,
  						attributes : {},
  						anyAttribute : null,
  						value : null,
  						any : null
  					};
  					this.buildStructure(context, structure);
  					this.structure = structure;
  				}
  			},
  			buildStructure : function(context, structure) {
  				if (Jsonix.Util.Type.exists(this.baseTypeInfo)) {
  					this.baseTypeInfo.buildStructure(context, structure);
  				}
  				for ( var index = 0; index < this.properties.length; index++) {
  					var propertyInfo = this.properties[index];
  					propertyInfo.buildStructure(context, structure);
  				}
  			},
  			unmarshal : function(context, input) {
  				this.build(context);
  				var result;
  
  				if (this.instanceFactory) {
  					result = new this.instanceFactory();
  				}
  				else
  				{
  					result = { TYPE_NAME : this.name };
  				}
  
  				if (input.eventType !== 1) {
  					throw new Error("Parser must be on START_ELEMENT to read a class info.");
  				}
  
  				// Read attributes
  				if (Jsonix.Util.Type.exists(this.structure.attributes)) {
  					var attributeCount = input.getAttributeCount();
  					if (attributeCount !== 0) {
  						for ( var index = 0; index < attributeCount; index++) {
  							var attributeNameKey = input
  									.getAttributeNameKey(index);
  							if (Jsonix.Util.Type
  									.exists(this.structure.attributes[attributeNameKey])) {
  								var attributeValue = input
  										.getAttributeValue(index);
  								if (Jsonix.Util.Type.isString(attributeValue)) {
  									var attributePropertyInfo = this.structure.attributes[attributeNameKey];
  									this.unmarshalPropertyValue(context, input,
  											attributePropertyInfo, result,
  											attributeValue);
  								}
  							}
  						}
  					}
  				}
  				// Read any attribute
  				if (Jsonix.Util.Type.exists(this.structure.anyAttribute)) {
  					var propertyInfo = this.structure.anyAttribute;
  					this
  							.unmarshalProperty(context, input, propertyInfo,
  									result);
  				}
  				// Read elements
  				if (Jsonix.Util.Type.exists(this.structure.elements)) {
  
  					var et = input.next();
  					while (et !== Jsonix.XML.Input.END_ELEMENT) {
  						if (et === Jsonix.XML.Input.START_ELEMENT) {
  							// New sub-element starts
  							var elementNameKey = input.getNameKey();
  							if (Jsonix.Util.Type
  									.exists(this.structure.elements[elementNameKey])) {
  								var elementPropertyInfo = this.structure.elements[elementNameKey];
  								this.unmarshalProperty(context, input,
  										elementPropertyInfo, result);
  							} else if (Jsonix.Util.Type
  									.exists(this.structure.any)) {
  								// TODO Refactor
  
  								var anyPropertyInfo = this.structure.any;
  								this.unmarshalProperty(context, input,
  										anyPropertyInfo, result);
  							} else {
  								// TODO optionally report a validation error that the element is not expected
  								et = input.skipElement();
  							}
  						} else if ((et === Jsonix.XML.Input.CHARACTERS || et === Jsonix.XML.Input.CDATA || et === Jsonix.XML.Input.ENTITY_REFERENCE)) {
  							if (Jsonix.Util.Type.exists(this.structure.mixed))
  							{
  								// Characters and structure has a mixed property
  								var mixedPropertyInfo = this.structure.mixed;
  								this.unmarshalProperty(context, input,
  										mixedPropertyInfo, result);
  							}
  						} else if (et === Jsonix.XML.Input.SPACE || et === Jsonix.XML.Input.COMMENT	|| et === Jsonix.XML.Input.PROCESSING_INSTRUCTION) {
  							// Ignore
  						} else {
  							throw new Error("Illegal state: unexpected event type [" + et	+ "].");
  						}
  						et = input.next();
  					}
  				} else if (Jsonix.Util.Type.exists(this.structure.value)) {
  					var valuePropertyInfo = this.structure.value;
  					this.unmarshalProperty(context, input, valuePropertyInfo,
  							result);
  				} else {
  					// Just skip everything
  					input.nextTag();
  				}
  				if (input.eventType !== 2) {
  					throw new Error("Illegal state: must be END_ELEMENT.");
  				}
  				return result;
  			},
  			unmarshalProperty : function(context, input, propertyInfo, result) {
  				var propertyValue = propertyInfo
  						.unmarshal(context, input, this);
  				propertyInfo.setProperty(result, propertyValue);
  			},
  			unmarshalPropertyValue : function(context, input, propertyInfo,
  					result, value) {
  				var propertyValue = propertyInfo.unmarshalValue(value, context, input, this);
  				propertyInfo.setProperty(result, propertyValue);
  			},
  			marshal : function(value, context, output, scope) {
  				if (this.isMarshallable(value, context, scope))
  				{
  					// TODO This must be reworked
  					if (Jsonix.Util.Type.exists(this.baseTypeInfo)) {
  						this.baseTypeInfo.marshal(value, context, output);
  					}
  					for ( var index = 0; index < this.properties.length; index++) {
  						var propertyInfo = this.properties[index];
  						var propertyValue = value[propertyInfo.name];
  						if (Jsonix.Util.Type.exists(propertyValue)) {
  							propertyInfo.marshal(propertyValue, context, output, this);
  						}
  					}
  				}
  				else
  				{
  					// Otherwise if there is just one property, use this property to marshal
  					if (this.structure.value)
  					{
  						var valuePropertyInfo = this.structure.value;
  						valuePropertyInfo.marshal(value, context, output, this);
  					}
  					else if (this.properties.length === 1)
  					{
  						var singlePropertyInfo = this.properties[0];
  						singlePropertyInfo.marshal(value, context, output, this);
  					}
  					else
  					{
  						// TODO throw an error
  						throw new Error("The passed value [" + value + "] is not an object and there is no single suitable property to marshal it.");
  					}
  				}
  			},
  			// Checks if the value is marshallable
  			isMarshallable : function(value, context, scope) {
  				return this.isInstance(value, context, scope) || (Jsonix.Util.Type.isObject(value) && !Jsonix.Util.Type.isArray(value));
  			},
  			isInstance : function(value, context, scope) {
  				if (this.instanceFactory) {
  					return value instanceof this.instanceFactory;
  				}
  				else {
  					return Jsonix.Util.Type.isObject(value) && Jsonix.Util.Type.isString(value.TYPE_NAME) && value.TYPE_NAME === this.name;
  				}
  			},
  
  			// Obsolete, left for backwards compatibility
  			b : function(baseTypeInfo) {
  				Jsonix.Util.Ensure.ensureObject(baseTypeInfo);
  				this.baseTypeInfo = baseTypeInfo;
  				return this;
  			},
  			// Obsolete, left for backwards compatibility
  			ps : function() {
  				return this;
  			},
  			p : function(mapping) {
  				Jsonix.Util.Ensure.ensureObject(mapping);
  				// If mapping is an instance of the property class
  				if (mapping instanceof Jsonix.Model.PropertyInfo) {
  					this.addProperty(mapping);
  				}
  				// Else create it via generic mapping configuration
  				else {
  					mapping = Jsonix.Util.Type.cloneObject(mapping);
  					var type = mapping.type||mapping.t||'element';
  					// Locate the creator function
  					if (Jsonix.Util.Type
  							.isFunction(this.propertyInfoCreators[type])) {
  						var propertyInfoCreator = this.propertyInfoCreators[type];
  						// Call the creator function
  						propertyInfoCreator.call(this, mapping);
  					} else {
  						throw new Error("Unknown property info type [" + type + "].");
  					}
  				}
  			},
  			aa : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this
  						.addProperty(new this.mappingStyle.anyAttributePropertyInfo(
  								mapping, {
  									mappingStyle : this.mappingStyle
  								}));
  			},
  			ae : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this
  						.addProperty(new this.mappingStyle.anyElementPropertyInfo(
  								mapping, {
  									mappingStyle : this.mappingStyle
  								}));
  			},
  			a : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this.addProperty(new this.mappingStyle.attributePropertyInfo(
  						mapping, {
  							mappingStyle : this.mappingStyle
  						}));
  			},
  			em : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this
  						.addProperty(new this.mappingStyle.elementMapPropertyInfo(
  								mapping, {
  									mappingStyle : this.mappingStyle
  								}));
  			},
  			e : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this.addProperty(new this.mappingStyle.elementPropertyInfo(
  						mapping, {
  							mappingStyle : this.mappingStyle
  						}));
  			},
  			es : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this.addProperty(new this.mappingStyle.elementsPropertyInfo(
  						mapping, {
  							mappingStyle : this.mappingStyle
  						}));
  			},
  			er : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this
  						.addProperty(new this.mappingStyle.elementRefPropertyInfo(
  								mapping, {
  									mappingStyle : this.mappingStyle
  								}));
  			},
  			ers : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this
  						.addProperty(new this.mappingStyle.elementRefsPropertyInfo(
  								mapping, {
  									mappingStyle : this.mappingStyle
  								}));
  			},
  			v : function(mapping) {
  				this.addDefaultNamespaces(mapping);
  				return this.addProperty(new this.mappingStyle.valuePropertyInfo(
  						mapping, {
  							mappingStyle : this.mappingStyle
  						}));
  			},
  			addDefaultNamespaces : function(mapping) {
  				if (Jsonix.Util.Type.isObject(mapping)) {
  					if (!Jsonix.Util.Type
  							.isString(mapping.defaultElementNamespaceURI)) {
  						mapping.defaultElementNamespaceURI = this.defaultElementNamespaceURI;
  					}
  					if (!Jsonix.Util.Type
  							.isString(mapping.defaultAttributeNamespaceURI)) {
  						mapping.defaultAttributeNamespaceURI = this.defaultAttributeNamespaceURI;
  					}
  				}
  			},
  			addProperty : function(property) {
  				this.properties.push(property);
  				this.propertiesMap[property.name] = property;
  				return this;
  			},
  			CLASS_NAME : 'Jsonix.Model.ClassInfo'
  		});
  Jsonix.Model.ClassInfo.prototype.propertyInfoCreators = {
  	"aa" : Jsonix.Model.ClassInfo.prototype.aa,
  	"anyAttribute" : Jsonix.Model.ClassInfo.prototype.aa,
  	"ae" : Jsonix.Model.ClassInfo.prototype.ae,
  	"anyElement" : Jsonix.Model.ClassInfo.prototype.ae,
  	"a" : Jsonix.Model.ClassInfo.prototype.a,
  	"attribute" : Jsonix.Model.ClassInfo.prototype.a,
  	"em" : Jsonix.Model.ClassInfo.prototype.em,
  	"elementMap" : Jsonix.Model.ClassInfo.prototype.em,
  	"e" : Jsonix.Model.ClassInfo.prototype.e,
  	"element" : Jsonix.Model.ClassInfo.prototype.e,
  	"es" : Jsonix.Model.ClassInfo.prototype.es,
  	"elements" : Jsonix.Model.ClassInfo.prototype.es,
  	"er" : Jsonix.Model.ClassInfo.prototype.er,
  	"elementRef" : Jsonix.Model.ClassInfo.prototype.er,
  	"ers" : Jsonix.Model.ClassInfo.prototype.ers,
  	"elementRefs" : Jsonix.Model.ClassInfo.prototype.ers,
  	"v" : Jsonix.Model.ClassInfo.prototype.v,
  	"value" : Jsonix.Model.ClassInfo.prototype.v
  };
  
  Jsonix.Model.EnumLeafInfo = Jsonix.Class(Jsonix.Model.TypeInfo, {
  	name : null,
  	baseTypeInfo : 'String',
  	entries : null,
  	keys : null,
  	values : null,
  	built : false,
  	initialize : function(mapping) {
  		Jsonix.Model.TypeInfo.prototype.initialize.apply(this, []);
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		
  		var n = mapping.name||mapping.n||undefined;
  		Jsonix.Util.Ensure.ensureString(n);
  		this.name = n;
  		
  		var bti = mapping.baseTypeInfo||mapping.bti||'String';
  		this.baseTypeInfo = bti;
  		
  		var vs = mapping.values||mapping.vs||undefined;
  		Jsonix.Util.Ensure.ensureExists(vs);
  		if (!(Jsonix.Util.Type.isObject(vs) || Jsonix.Util.Type.isArray(vs))) {
  			throw new Error('Enum values must be either an array or an object.');
  		}
  		else
  		{
  			this.entries = vs;
  		}		
  	},
  	build : function(context) {
  		if (!this.built) {
  			this.baseTypeInfo = context.resolveTypeInfo(this.baseTypeInfo, this.module);
  			this.baseTypeInfo.build(context);
  			var items = this.entries;
  			var entries = {};
  			var keys = [];
  			var values = [];
  			var index = 0;
  			var key;
  			var value;
  			// If values is an array, process individual items
  			if (Jsonix.Util.Type.isArray(items))
  			{
  				// Build properties in this context
  				for (index = 0; index < items.length; index++) {
  					value = items[index];
  					if (Jsonix.Util.Type.isString(value)) {
  						key = value;
  						if (!(Jsonix.Util.Type.isFunction(this.baseTypeInfo.parse)))
  						{
  							throw new Error('Enum value is provided as string but the base type ['+this.baseTypeInfo.name+'] of the enum info [' + this.name + '] does not implement the parse method.');
  						}
  						// Using null as input since input is not available
  						value = this.baseTypeInfo.parse(value, context, null, this);
  					}
  					else
  					{
  						if (this.baseTypeInfo.isInstance(value, context, this))
  						{
  							if (!(Jsonix.Util.Type.isFunction(this.baseTypeInfo.print)))
  							{
  								throw new Error('The base type ['+this.baseTypeInfo.name+'] of the enum info [' + this.name + '] does not implement the print method, unable to produce the enum key as string.');
  							}
  							// Using null as output since output is not available at this moment
  							key = this.baseTypeInfo.print(value, context, null, this);
  						}
  						else
  						{
  							throw new Error('Enum value [' + value + '] is not an instance of the enum base type [' + this.baseTypeInfo.name + '].');
  						}
  					}
  					entries[key] = value;
  					keys[index] = key;
  					values[index] = value;
  				}
  			}
  			else if (Jsonix.Util.Type.isObject(items))
  			{
  				for (key in items) {
  					if (items.hasOwnProperty(key)) {
  						value = items[key];
  						if (Jsonix.Util.Type.isString(value)) {
  							if (!(Jsonix.Util.Type.isFunction(this.baseTypeInfo.parse)))
  							{
  								throw new Error('Enum value is provided as string but the base type ['+this.baseTypeInfo.name+'] of the enum info [' + this.name + '] does not implement the parse method.');
  							}
  							// Using null as input since input is not available
  							value = this.baseTypeInfo.parse(value, context, null, this);
  						}
  						else
  						{
  							if (!this.baseTypeInfo.isInstance(value, context, this))
  							{
  								throw new Error('Enum value [' + value + '] is not an instance of the enum base type [' + this.baseTypeInfo.name + '].');
  							}
  						}
  						entries[key] = value;
  						keys[index] = key;
  						values[index] = value;
  						index++;
  					}
  				}
  			}
  			else {
  				throw new Error('Enum values must be either an array or an object.');
  			}
  			this.entries = entries;
  			this.keys = keys;
  			this.values = values;
  			this.built = true;
  		}
  	},
  	unmarshal : function(context, input, scope) {
  		var text = input.getElementText();
  		return this.parse(text, context, input, scope);
  	},
  	marshal : function(value, context, output, scope) {
  		if (Jsonix.Util.Type.exists(value)) {
  			output.writeCharacters(this.reprint(value, context, output, scope));
  		}
  	},
  	reprint : function(value, context, output, scope) {
  		if (Jsonix.Util.Type.isString(value) && !this.isInstance(value, context, scope)) {
  			// Using null as input since input is not available
  			return this.print(this.parse(value, context, null, scope), context, output, scope);
  		} else {
  			return this.print(value, context, output, scope);
  		}
  	},
  	print : function(value, context, output, scope) {
  		for (var index = 0; index < this.values.length; index++)
  		{
  			if (this.values[index] === value)
  			{
  				return this.keys[index];
  			}
  		}
  		throw new Error('Value [' + value + '] is invalid for the enum type [' + this.name + '].');
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		if (this.entries.hasOwnProperty(text))
  		{
  			return this.entries[text];
  		}
  		else
  		{
  			throw new Error('Value [' + text + '] is invalid for the enum type [' + this.name + '].');
  		}
  	},
  	isInstance : function(value, context, scope) {
  		for (var index = 0; index < this.values.length; index++)
  		{
  			if (this.values[index] === value)
  			{
  				return true;
  			}
  		}
  		return false;
  	},
  	CLASS_NAME : 'Jsonix.Model.EnumLeafInfo'
  });
  Jsonix.Model.ElementInfo = Jsonix.Class({
  	module: null,			
  	elementName : null,
  	typeInfo : null,
  	substitutionHead : null,
  	scope : null,
  	built : false,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		
  		var dens = mapping.defaultElementNamespaceURI||mapping.dens||'';
  		this.defaultElementNamespaceURI = dens;
  		
  		var en = mapping.elementName || mapping.en||undefined;
  		if (Jsonix.Util.Type.isObject(en)) {
  			this.elementName = Jsonix.XML.QName.fromObject(en);
  		} else {
  			Jsonix.Util.Ensure.ensureString(en);
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, en);
  		}
  		
  		var ti = mapping.typeInfo||mapping.ti||'String';
  		this.typeInfo = ti;
  		
  		var sh = mapping.substitutionHead||mapping.sh||null;
  		this.substitutionHead = sh;
  		
  		var sc = mapping.scope||mapping.sc||null;
  		this.scope = sc;
  	},
  	build : function(context) {
  		// If element info is not yet built
  		if (!this.built) {
  			this.typeInfo = context.resolveTypeInfo(this.typeInfo, this.module);
  			this.scope = context.resolveTypeInfo(this.scope, this.module);
  			this.built = true;
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementInfo'
  });
  Jsonix.Model.PropertyInfo = Jsonix.Class({
  	name : null,
  	collection : false,
  	targetNamespace : '',
  	defaultElementNamespaceURI : '',
  	defaultAttributeNamespaceURI : '',
  	built : false,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		var n = mapping.name || mapping.n || undefined;
  		Jsonix.Util.Ensure.ensureString(n);
  		this.name = n;
  		var dens = mapping.defaultElementNamespaceURI || mapping.dens || mapping.targetNamespace || mapping.tns || '';
  		this.defaultElementNamespaceURI = dens;
  		var tns = mapping.targetNamespace || mapping.tns || mapping.defaultElementNamespaceURI || mapping.dens || this.defaultElementNamespaceURI;
  		this.targetNamespace = tns;
  		var dans = mapping.defaultAttributeNamespaceURI || mapping.dans || '';
  		this.defaultAttributeNamespaceURI = dans;
  		var col = mapping.collection || mapping.col || false;
  		this.collection = col;
  		var rq = mapping.required || mapping.rq || false;
  		this.required = rq;
  		if (this.collection) {
  			var mno;
  			if (Jsonix.Util.Type.isNumber(mapping.minOccurs)) {
  				mno = mapping.minOccurs;
  			}
  			else if (Jsonix.Util.Type.isNumber(mapping.mno)) {
  				mno = mapping.mno;
  			}
  			else {
  				mno = 1;
  			}
  			this.minOccurs = mno;
  			var mxo;
  			if (Jsonix.Util.Type.isNumber(mapping.maxOccurs)) {
  				mxo = mapping.maxOccurs;
  			}
  			else if (Jsonix.Util.Type.isNumber(mapping.mxo)) {
  				mxo = mapping.mxo;
  			}
  			else {
  				mxo = null;
  			}
  			this.maxOccurs = mxo;
  		}
  	},
  	build : function(context, module) {
  		if (!this.built) {
  			this.doBuild(context, module);
  			this.built = true;
  		}
  	},
  	doBuild : function(context, module) {
  		throw new Error("Abstract method [doBuild].");
  	},
  	buildStructure : function(context, structure) {
  		throw new Error("Abstract method [buildStructure].");
  	},
  	setProperty : function(object, value) {
  		if (Jsonix.Util.Type.exists(value)) {
  			if (this.collection) {
  				Jsonix.Util.Ensure.ensureArray(value, 'Collection property requires an array value.');
  				if (!Jsonix.Util.Type.exists(object[this.name])) {
  					object[this.name] = [];
  				}
  				for (var index = 0; index < value.length; index++) {
  					object[this.name].push(value[index]);
  				}
  
  			} else {
  				object[this.name] = value;
  			}
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.PropertyInfo'
  });
  Jsonix.Model.AnyAttributePropertyInfo = Jsonix.Class(Jsonix.Model.PropertyInfo, {
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.PropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  	},
  	unmarshal : function(context, input, scope) {
  		var attributeCount = input.getAttributeCount();
  		if (attributeCount === 0) {
  			return null;
  		} else {
  			var result = {};
  			for ( var index = 0; index < attributeCount; index++) {
  				var value = input.getAttributeValue(index);
  				if (Jsonix.Util.Type.isString(value)) {
  					var propertyName = this.convertFromAttributeName(input.getAttributeName(index), context, input, scope);
  					result[propertyName] = value;
  				}
  			}
  			return result;
  		}
  	},
  	marshal : function(value, context, output, scope) {
  		if (!Jsonix.Util.Type.isObject(value)) {
  			// Nothing to do
  			return;
  		}
  		for ( var propertyName in value) {
  			if (value.hasOwnProperty(propertyName)) {
  				var propertyValue = value[propertyName];
  				if (Jsonix.Util.Type.isString(propertyValue)) {
  					var attributeName = this.convertToAttributeName(propertyName, context, output, scope);
  					output.writeAttribute(attributeName, propertyValue);
  				}
  			}
  		}
  	},
  	convertFromAttributeName : function(attributeName, context, input, scope) {
  		return attributeName.key;
  	},
  	convertToAttributeName : function(propertyName, context, output, scope) {
  		return Jsonix.XML.QName.fromObjectOrString(propertyName, context);
  	},
  	doBuild : function(context, module)	{
  		// Nothing to do
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		// if (Jsonix.Util.Type.exists(structure.anyAttribute))
  		// {
  		// // TODO better exception
  		// throw new Error("The structure already defines an any attribute
  		// property.");
  		// } else
  		// {
  		structure.anyAttribute = this;
  		// }
  	},
  	CLASS_NAME : 'Jsonix.Model.AnyAttributePropertyInfo'
  });
  Jsonix.Model.AnyAttributePropertyInfo.Simplified = Jsonix.Class(Jsonix.Model.AnyAttributePropertyInfo, {
  	convertFromAttributeName : function(attributeName, context, input, scope)
  	{
  		return attributeName.toCanonicalString(context);
  	}
  });
  
  Jsonix.Model.SingleTypePropertyInfo = Jsonix.Class(Jsonix.Model.PropertyInfo, {
  	typeInfo : 'String',
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.PropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var ti = mapping.typeInfo || mapping.ti || 'String';
  		this.typeInfo = ti;
  	},
  	doBuild : function(context, module) {
  		this.typeInfo = context.resolveTypeInfo(this.typeInfo, module);
  	},
  	unmarshalValue : function(value, context, input, scope) {
  		return this.parse(value, context, input, scope);
  	},
  	parse : function(value, context, input, scope) {
  		return this.typeInfo.parse(value, context, input, scope);
  	},
  	print : function(value, context, output, scope) {
  		return this.typeInfo.reprint(value, context, output, scope);
  	},
  	CLASS_NAME : 'Jsonix.Model.SingleTypePropertyInfo'
  });
  
  Jsonix.Model.AttributePropertyInfo = Jsonix.Class(Jsonix.Model.SingleTypePropertyInfo, {
  	attributeName : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.SingleTypePropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var an = mapping.attributeName||mapping.an||undefined;
  		if (Jsonix.Util.Type.isObject(an)) {
  			this.attributeName = Jsonix.XML.QName.fromObject(an);
  		} else if (Jsonix.Util.Type.isString(an)) {
  			this.attributeName = new Jsonix.XML.QName(this.defaultAttributeNamespaceURI, an);
  		} else {
  			this.attributeName = new Jsonix.XML.QName(this.defaultAttributeNamespaceURI, this.name);
  		}
  	},
  	unmarshal : function(context, input, scope) {
  		var attributeCount = input.getAttributeCount();
  		var result = null;
  		for ( var index = 0; index < attributeCount; index++) {
  			var attributeNameKey = input.getAttributeNameKey(index);
  			if (this.attributeName.key === attributeNameKey) {
  				var attributeValue = input.getAttributeValue(index);
  				if (Jsonix.Util.Type.isString(attributeValue)) {
  					result = this.unmarshalValue(attributeValue, context, input, scope);
  				}
  			}
  		}
  		return result;
  	},
  	marshal : function(value, context, output, scope) {
  		if (Jsonix.Util.Type.exists(value)) {
  			output.writeAttribute(this.attributeName, this.print(value, context, output, scope));
  		}
  
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		Jsonix.Util.Ensure.ensureObject(structure.attributes);
  		var key = this.attributeName.key;
  		// if (Jsonix.Util.Type.exists(structure.attributes[key])) {
  		// // TODO better exception
  		// throw new Error("The structure already defines an attribute for the key
  		// ["
  		// + key + "].");
  		// } else
  		// {
  		structure.attributes[key] = this;
  		// }
  	},
  	CLASS_NAME : 'Jsonix.Model.AttributePropertyInfo'
  });
  
  Jsonix.Model.ValuePropertyInfo = Jsonix.Class(Jsonix.Model.SingleTypePropertyInfo, {
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.SingleTypePropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  
  		var c = mapping.asCDATA || mapping.c || false;
  		this.asCDATA = c;
  	},
  	unmarshal : function(context, input, scope) {
  		var text = input.getElementText();
  		return this.unmarshalValue(text, context, input, scope);
  	},
  	marshal : function(value, context, output, scope) {
  		if (!Jsonix.Util.Type.exists(value)) {
  			return;
  		}
  
  		if (this.asCDATA) {
  			output.writeCdata(this.print(value, context, output, scope));
  		} else {
  			output.writeCharacters(this.print(value, context, output, scope));
  		}
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		// if (Jsonix.Util.Type.exists(structure.value)) {
  		// // TODO better exception
  		// throw new Error("The structure already defines a value
  		// property.");
  		// } else
  		if (Jsonix.Util.Type.exists(structure.elements)) {
  			// TODO better exception
  			throw new Error("The structure already defines element mappings, it cannot define a value property.");
  		} else {
  			structure.value = this;
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.ValuePropertyInfo'
  });
  
  Jsonix.Model.AbstractElementsPropertyInfo = Jsonix.Class(Jsonix.Binding.Unmarshalls.Element, Jsonix.Binding.Unmarshalls.WrapperElement, Jsonix.Model.PropertyInfo, {
  	wrapperElementName : null,
  	allowDom : false,
  	allowTypedObject : true,
  	mixed : false,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.PropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var wen = mapping.wrapperElementName||mapping.wen||undefined;
  		if (Jsonix.Util.Type.isObject(wen)) {
  			this.wrapperElementName = Jsonix.XML.QName.fromObject(wen);
  		} else if (Jsonix.Util.Type.isString(wen)) {
  			this.wrapperElementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, wen);
  		} else {
  			this.wrapperElementName = null;
  		}
  	},
  	unmarshal : function(context, input, scope) {
  		var result = null;
  		var that = this;
  		var callback = function(value) {
  			if (that.collection) {
  				if (result === null) {
  					result = [];
  				}
  				result.push(value);
  
  			} else {
  				if (result === null) {
  					result = value;
  				} else {
  					// TODO Report validation error
  					throw new Error("Value already set.");
  				}
  			}
  		};
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			this.unmarshalWrapperElement(context, input, scope, callback);
  		} else {
  			this.unmarshalElement(context, input, scope, callback);
  		}
  		return result;
  	},
  	marshal : function(value, context, output, scope) {
  
  		if (!Jsonix.Util.Type.exists(value)) {
  			// Do nothing
  			return;
  		}
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			output.writeStartElement(this.wrapperElementName);
  		}
  
  		if (!this.collection) {
  			this.marshalElement(value, context, output, scope);
  		} else {
  			Jsonix.Util.Ensure.ensureArray(value);
  			// TODO Exception if not array
  			for ( var index = 0; index < value.length; index++) {
  				var item = value[index];
  				// TODO Exception if item does not exist
  				this.marshalElement(item, context, output, scope);
  			}
  		}
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			output.writeEndElement();
  		}
  	},
  	convertFromTypedNamedValue : function(elementValue, context, input, scope) {
  		return elementValue.value;
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		if (Jsonix.Util.Type.exists(structure.value)) {
  			// TODO better exception
  			throw new Error("The structure already defines a value property.");
  		} else if (!Jsonix.Util.Type.exists(structure.elements)) {
  			structure.elements = {};
  		}
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			structure.elements[this.wrapperElementName.key] = this;
  		} else {
  			this.buildStructureElements(context, structure);
  		}
  	},
  	buildStructureElements : function(context, structure) {
  		throw new Error("Abstract method [buildStructureElements].");
  	},
  	CLASS_NAME : 'Jsonix.Model.AbstractElementsPropertyInfo'
  });
  
  Jsonix.Model.ElementPropertyInfo = Jsonix.Class(Jsonix.Model.AbstractElementsPropertyInfo, Jsonix.Binding.Marshalls.Element, {
  	typeInfo : 'String',
  	elementName : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.AbstractElementsPropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var ti = mapping.typeInfo || mapping.ti || 'String';
  		if (Jsonix.Util.Type.isObject(ti)) {
  			this.typeInfo = ti;
  		} else {
  			Jsonix.Util.Ensure.ensureString(ti);
  			this.typeInfo = ti;
  		}
  		var en = mapping.elementName || mapping.en || undefined;
  		if (Jsonix.Util.Type.isObject(en)) {
  			this.elementName = Jsonix.XML.QName.fromObject(en);
  		} else if (Jsonix.Util.Type.isString(en)) {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, en);
  		} else {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, this.name);
  		}
  	},
  	getTypeInfoByElementName : function(elementName, context, scope) {
  		return this.typeInfo;
  	},
  	convertToTypedNamedValue : function(value, context, output, scope) {
  		return {
  			name : this.elementName,
  			value : value,
  			typeInfo : this.typeInfo
  		};
  	},
  	doBuild : function(context, module) {
  		this.typeInfo = context.resolveTypeInfo(this.typeInfo, module);
  	},
  	buildStructureElements : function(context, structure) {
  		structure.elements[this.elementName.key] = this;
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementPropertyInfo'
  });
  
  Jsonix.Model.ElementsPropertyInfo = Jsonix.Class(Jsonix.Model.AbstractElementsPropertyInfo, Jsonix.Binding.Marshalls.Element, {
  	elementTypeInfos : null,
  	elementTypeInfosMap : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.AbstractElementsPropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var etis = mapping.elementTypeInfos || mapping.etis || [];
  		Jsonix.Util.Ensure.ensureArray(etis);
  		this.elementTypeInfos = [];
  		for (var index = 0; index < etis.length; index++) {
  			this.elementTypeInfos[index] = Jsonix.Util.Type.cloneObject(etis[index]);
  		}
  	},
  	getTypeInfoByElementName : function(elementName, context, scope) {
  		return this.elementTypeInfosMap[elementName.key];
  	},
  	convertToTypedNamedValue : function(value, context, output, scope) {
  		for (var index = 0; index < this.elementTypeInfos.length; index++) {
  			var elementTypeInfo = this.elementTypeInfos[index];
  			var typeInfo = elementTypeInfo.typeInfo;
  			if (typeInfo.isInstance(value, context, scope)) {
  				var elementName = elementTypeInfo.elementName;
  				return {
  					name : elementName,
  					value : value,
  					typeInfo : typeInfo
  				};
  			}
  		}
  		// If xsi:type is supported
  		if (context.supportXsiType) {
  			// Find the actual type
  			var actualTypeInfo = context.getTypeInfoByValue(value);
  			if (actualTypeInfo && actualTypeInfo.typeName) {
  				for (var jndex = 0; jndex < this.elementTypeInfos.length; jndex++) {
  					var eti = this.elementTypeInfos[jndex];
  					var ti = eti.typeInfo;
  					// TODO Can be optimized
  					// Find an element type info which has a type info that is a
  					// supertype of the actual type info
  					if (actualTypeInfo.isBasedOn(ti)) {
  						var en = eti.elementName;
  						return {
  							name : en,
  							value : value,
  							typeInfo : ti
  						};
  					}
  				}
  			}
  		}
  		// TODO harmonize error handling. See also marshallElement. Error must
  		// only be on one place.
  		throw new Error("Could not find an element with type info supporting the value [" + value + "].");
  	},
  	doBuild : function(context, module) {
  		this.elementTypeInfosMap = {};
  		var etiti, etien;
  		for (var index = 0; index < this.elementTypeInfos.length; index++) {
  			var elementTypeInfo = this.elementTypeInfos[index];
  			Jsonix.Util.Ensure.ensureObject(elementTypeInfo);
  			etiti = elementTypeInfo.typeInfo || elementTypeInfo.ti || 'String';
  			elementTypeInfo.typeInfo = context.resolveTypeInfo(etiti, module);
  			etien = elementTypeInfo.elementName || elementTypeInfo.en || undefined;
  			elementTypeInfo.elementName = Jsonix.XML.QName.fromObjectOrString(etien, context, this.defaultElementNamespaceURI);
  			this.elementTypeInfosMap[elementTypeInfo.elementName.key] = elementTypeInfo.typeInfo;
  		}
  	},
  	buildStructureElements : function(context, structure) {
  		for (var index = 0; index < this.elementTypeInfos.length; index++) {
  			var elementTypeInfo = this.elementTypeInfos[index];
  			structure.elements[elementTypeInfo.elementName.key] = this;
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementsPropertyInfo'
  });
  
  Jsonix.Model.ElementMapPropertyInfo = Jsonix.Class(Jsonix.Model.AbstractElementsPropertyInfo, {
  	elementName : null,
  	key : null,
  	value : null,
  	entryTypeInfo : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.AbstractElementsPropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		// TODO Ensure correct argument
  		var k = mapping.key || mapping.k || undefined;
  		Jsonix.Util.Ensure.ensureObject(k);
  		var v = mapping.value || mapping.v || undefined;
  		Jsonix.Util.Ensure.ensureObject(v);
  		// TODO Ensure correct argument
  		var en = mapping.elementName || mapping.en || undefined;
  		if (Jsonix.Util.Type.isObject(en)) {
  			this.elementName = Jsonix.XML.QName.fromObject(en);
  		} else if (Jsonix.Util.Type.isString(en)) {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, en);
  		} else {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, this.name);
  		}
  		this.entryTypeInfo = new Jsonix.Model.ClassInfo({
  			name : 'Map<' + k.name + ',' + v.name + '>',
  			propertyInfos : [ k, v ]
  		});
  
  	},
  	unmarshal : function(context, input, scope) {
  		var result = null;
  		var that = this;
  		var callback = function(value) {
  
  			if (Jsonix.Util.Type.exists(value)) {
  				Jsonix.Util.Ensure.ensureObject(value, 'Map property requires an object.');
  				if (!Jsonix.Util.Type.exists(result)) {
  					result = {};
  				}
  				for ( var attributeName in value) {
  					if (value.hasOwnProperty(attributeName)) {
  						var attributeValue = value[attributeName];
  						if (that.collection) {
  							if (!Jsonix.Util.Type.exists(result[attributeName])) {
  								result[attributeName] = [];
  							}
  							result[attributeName].push(attributeValue);
  						} else {
  							if (!Jsonix.Util.Type.exists(result[attributeName])) {
  								result[attributeName] = attributeValue;
  							} else {
  								// TODO Report validation error
  								throw new Error("Value was already set.");
  							}
  						}
  					}
  				}
  			}
  		};
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			this.unmarshalWrapperElement(context, input, scope, callback);
  		} else {
  			this.unmarshalElement(context, input, scope, callback);
  		}
  		return result;
  	},
  	getTypeInfoByInputElement : function(context, input, scope) {
  		return this.entryTypeInfo;
  	},
  	convertFromTypedNamedValue : function(elementValue, context, input, scope) {
  		var entry = elementValue.value;
  		var result = {};
  		if (Jsonix.Util.Type.isString(entry[this.key.name])) {
  			result[entry[this.key.name]] = entry[this.value.name];
  		}
  		return result;
  	},
  	marshal : function(value, context, output, scope) {
  
  		if (!Jsonix.Util.Type.exists(value)) {
  			// Do nothing
  			return;
  		}
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			output.writeStartElement(this.wrapperElementName);
  		}
  
  		this.marshalElement(value, context, output, scope);
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			output.writeEndElement();
  		}
  	},
  	marshalElement : function(value, context, output, scope) {
  		if (!!value) {
  			for ( var attributeName in value) {
  				if (value.hasOwnProperty(attributeName)) {
  					var attributeValue = value[attributeName];
  					if (!this.collection) {
  						var singleEntry = {};
  						singleEntry[this.key.name] = attributeName;
  						singleEntry[this.value.name] = attributeValue;
  						output.writeStartElement(this.elementName);
  						this.entryTypeInfo.marshal(singleEntry, context, output, scope);
  						output.writeEndElement();
  
  					} else {
  						for (var index = 0; index < attributeValue.length; index++) {
  							var collectionEntry = {};
  							collectionEntry[this.key.name] = attributeName;
  							collectionEntry[this.value.name] = attributeValue[index];
  							output.writeStartElement(this.elementName);
  							this.entryTypeInfo.marshal(collectionEntry, context, output, scope);
  							output.writeEndElement();
  						}
  					}
  				}
  			}
  		}
  	},
  	doBuild : function(context, module) {
  		this.entryTypeInfo.build(context, module);
  		// TODO get property by name
  		this.key = this.entryTypeInfo.properties[0];
  		this.value = this.entryTypeInfo.properties[1];
  	},
  	buildStructureElements : function(context, structure) {
  		structure.elements[this.elementName.key] = this;
  	},
  	setProperty : function(object, value) {
  		if (Jsonix.Util.Type.exists(value)) {
  			Jsonix.Util.Ensure.ensureObject(value, 'Map property requires an object.');
  			if (!Jsonix.Util.Type.exists(object[this.name])) {
  				object[this.name] = {};
  			}
  			var map = object[this.name];
  			for ( var attributeName in value) {
  				if (value.hasOwnProperty(attributeName)) {
  					var attributeValue = value[attributeName];
  					if (this.collection) {
  						if (!Jsonix.Util.Type.exists(map[attributeName])) {
  							map[attributeName] = [];
  						}
  
  						for (var index = 0; index < attributeValue.length; index++) {
  							map[attributeName].push(attributeValue[index]);
  						}
  					} else {
  						map[attributeName] = attributeValue;
  					}
  				}
  			}
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementMapPropertyInfo'
  });
  
  Jsonix.Model.AbstractElementRefsPropertyInfo = Jsonix.Class(Jsonix.Binding.Marshalls.Element, Jsonix.Binding.Marshalls.Element.AsElementRef, Jsonix.Binding.Unmarshalls.Element, Jsonix.Binding.Unmarshalls.WrapperElement, Jsonix.Binding.Unmarshalls.Element.AsElementRef, Jsonix.Model.PropertyInfo, {
  	wrapperElementName : null,
  	allowDom : true,
  	allowTypedObject : true,
  	mixed : true,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping, 'Mapping must be an object.');
  		Jsonix.Model.PropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var wen = mapping.wrapperElementName || mapping.wen || undefined;
  		if (Jsonix.Util.Type.isObject(wen)) {
  			this.wrapperElementName = Jsonix.XML.QName.fromObject(wen);
  		} else if (Jsonix.Util.Type.isString(wen)) {
  			this.wrapperElementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, wen);
  		} else {
  			this.wrapperElementName = null;
  		}
  		var dom = Jsonix.Util.Type.defaultValue(mapping.allowDom, mapping.dom, true);
  		var typed = Jsonix.Util.Type.defaultValue(mapping.allowTypedObject, mapping.typed, true);
  		var mx = Jsonix.Util.Type.defaultValue(mapping.mixed, mapping.mx, true);
  		this.allowDom = dom;
  		this.allowTypedObject = typed;
  		this.mixed = mx;
  	},
  	unmarshal : function(context, input, scope) {
  		var result = null;
  		var that = this;
  		var callback = function(value) {
  			if (that.collection) {
  				if (result === null) {
  					result = [];
  				}
  				result.push(value);
  
  			} else {
  				if (result === null) {
  					result = value;
  				} else {
  					// TODO Report validation error
  					throw new Error("Value already set.");
  				}
  			}
  		};
  
  		var et = input.eventType;
  		if (et === Jsonix.XML.Input.START_ELEMENT) {
  			if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  				this.unmarshalWrapperElement(context, input, scope, callback);
  			} else {
  				this.unmarshalElement(context, input, scope, callback);
  			}
  		} else if (this.mixed && (et === Jsonix.XML.Input.CHARACTERS || et === Jsonix.XML.Input.CDATA || et === Jsonix.XML.Input.ENTITY_REFERENCE)) {
  			callback(input.getText());
  		} else if (et === Jsonix.XML.Input.SPACE || et === Jsonix.XML.Input.COMMENT || et === Jsonix.XML.Input.PROCESSING_INSTRUCTION) {
  			// Skip whitespace
  		} else {
  			// TODO better exception
  			throw new Error("Illegal state: unexpected event type [" + et + "].");
  		}
  		return result;
  	},
  	marshal : function(value, context, output, scope) {
  
  		if (Jsonix.Util.Type.exists(value)) {
  			if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  				output.writeStartElement(this.wrapperElementName);
  			}
  
  			if (!this.collection) {
  				this.marshalItem(value, context, output, scope);
  			} else {
  				Jsonix.Util.Ensure.ensureArray(value, 'Collection property requires an array value.');
  				for (var index = 0; index < value.length; index++) {
  					var item = value[index];
  					this.marshalItem(item, context, output, scope);
  				}
  			}
  
  			if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  				output.writeEndElement();
  			}
  		}
  
  	},
  	marshalItem : function(value, context, output, scope) {
  		if (Jsonix.Util.Type.isString(value)) {
  			if (!this.mixed) {
  				// TODO
  				throw new Error("Property is not mixed, can't handle string values.");
  			} else {
  				output.writeCharacters(value);
  			}
  		} else if (this.allowDom && Jsonix.Util.Type.exists(value.nodeType)) {
  			// DOM node
  			output.writeNode(value);
  		} else if (Jsonix.Util.Type.isObject(value)) {
  			this.marshalElement(value, context, output, scope);
  
  		} else {
  			if (this.mixed) {
  				throw new Error("Unsupported content type, either objects or strings are supported.");
  			} else {
  				throw new Error("Unsupported content type, only objects are supported.");
  			}
  		}
  
  	},
  	getTypeInfoByElementName : function(elementName, context, scope) {
  		var propertyElementTypeInfo = this.getPropertyElementTypeInfo(elementName, context);
  		if (Jsonix.Util.Type.exists(propertyElementTypeInfo)) {
  			return propertyElementTypeInfo.typeInfo;
  		} else {
  			var contextElementTypeInfo = context.getElementInfo(elementName, scope);
  			if (Jsonix.Util.Type.exists(contextElementTypeInfo)) {
  				return contextElementTypeInfo.typeInfo;
  			} else {
  				return undefined;
  			}
  		}
  	},
  	getPropertyElementTypeInfo : function(elementName, context) {
  		throw new Error("Abstract method [getPropertyElementTypeInfo].");
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		if (Jsonix.Util.Type.exists(structure.value)) {
  			// TODO better exception
  			throw new Error("The structure already defines a value property.");
  		} else if (!Jsonix.Util.Type.exists(structure.elements)) {
  			structure.elements = {};
  		}
  
  		if (Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			structure.elements[this.wrapperElementName.key] = this;
  		} else {
  			this.buildStructureElements(context, structure);
  		}
  
  		// if (Jsonix.Util.Type.exists(structure.elements[key]))
  		// {
  		// // TODO better exception
  		// throw new Error("The structure already defines an element for
  		// the key ["
  		// + key + "].");
  		// } else
  		// {
  		// structure.elements[key] = this;
  		// }
  
  		if ((this.allowDom || this.allowTypedObject)) {
  			structure.any = this;
  		}
  		if (this.mixed && !Jsonix.Util.Type.exists(this.wrapperElementName)) {
  			// if (Jsonix.Util.Type.exists(structure.mixed)) {
  			// // TODO better exception
  			// throw new Error("The structure already defines the mixed
  			// property.");
  			// } else
  			// {
  			structure.mixed = this;
  			// }
  		}
  	},
  	buildStructureElements : function(context, structure) {
  		throw new Error("Abstract method [buildStructureElements].");
  	},
  	buildStructureElementTypeInfos : function(context, structure, elementTypeInfo) {
  		structure.elements[elementTypeInfo.elementName.key] = this;
  		var substitutionMembers = context.getSubstitutionMembers(elementTypeInfo.elementName);
  		if (Jsonix.Util.Type.isArray(substitutionMembers)) {
  			for (var jndex = 0; jndex < substitutionMembers.length; jndex++) {
  				var substitutionElementInfo = substitutionMembers[jndex];
  				this.buildStructureElementTypeInfos(context, structure, substitutionElementInfo);
  			}
  
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.AbstractElementRefsPropertyInfo'
  });
  Jsonix.Model.ElementRefPropertyInfo = Jsonix.Class(Jsonix.Model.AbstractElementRefsPropertyInfo, {
  	typeInfo : 'String',
  	elementName : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.AbstractElementRefsPropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		// TODO Ensure correct argument
  		var ti = mapping.typeInfo || mapping.ti || 'String';
  		if (Jsonix.Util.Type.isObject(ti)) {
  			this.typeInfo = ti;
  		} else {
  			Jsonix.Util.Ensure.ensureString(ti);
  			this.typeInfo = ti;
  		}
  		var en = mapping.elementName || mapping.en || undefined;
  		if (Jsonix.Util.Type.isObject(en)) {
  			this.elementName = Jsonix.XML.QName.fromObject(en);
  		} else if (Jsonix.Util.Type.isString(en)) {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, en);
  		} else {
  			this.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, this.name);
  		}
  	},
  	getPropertyElementTypeInfo : function(elementName, context) {
  		var name = Jsonix.XML.QName.fromObjectOrString(elementName, context);
  
  		if (name.key === this.elementName.key) {
  			return this;
  		} else {
  			return null;
  		}
  	},
  	doBuild : function(context, module) {
  		this.typeInfo = context.resolveTypeInfo(this.typeInfo, module);
  	},
  	buildStructureElements : function(context, structure) {
  		this.buildStructureElementTypeInfos(context, structure, this);
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementRefPropertyInfo'
  });
  Jsonix.Model.ElementRefPropertyInfo.Simplified = Jsonix.Class(Jsonix.Model.ElementRefPropertyInfo, Jsonix.Binding.Unmarshalls.Element.AsSimplifiedElementRef, {
  	CLASS_NAME : 'Jsonix.Model.ElementRefPropertyInfo.Simplified'
  });
  Jsonix.Model.ElementRefsPropertyInfo = Jsonix.Class(Jsonix.Model.AbstractElementRefsPropertyInfo, {
  	elementTypeInfos : null,
  	elementTypeInfosMap : null,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.AbstractElementRefsPropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		// TODO Ensure correct arguments
  		var etis = mapping.elementTypeInfos || mapping.etis || [];
  		Jsonix.Util.Ensure.ensureArray(etis);
  		this.elementTypeInfos = [];
  		for (var index = 0; index < etis.length; index++)
  		{
  			this.elementTypeInfos[index] = Jsonix.Util.Type.cloneObject(etis[index]);
  		}
  	},
  	getPropertyElementTypeInfo : function(elementName, context) {
  		var name = Jsonix.XML.QName.fromObjectOrString(elementName, context);
  
  		var typeInfo = this.elementTypeInfosMap[name.key];
  		if (Jsonix.Util.Type.exists(typeInfo)) {
  			return {
  				elementName : name,
  				typeInfo : typeInfo
  			};
  		} else {
  			return null;
  		}
  	},
  	doBuild : function(context, module) {
  		this.elementTypeInfosMap = {};
  		var etiti, etien;
  		for (var index = 0; index < this.elementTypeInfos.length; index++) {
  			var elementTypeInfo = this.elementTypeInfos[index];
  			Jsonix.Util.Ensure.ensureObject(elementTypeInfo);
  			etiti = elementTypeInfo.typeInfo || elementTypeInfo.ti || 'String';
  			elementTypeInfo.typeInfo = context.resolveTypeInfo(etiti, module);
  			etien = elementTypeInfo.elementName || elementTypeInfo.en || undefined;
  			elementTypeInfo.elementName = Jsonix.XML.QName.fromObjectOrString(etien, context, this.defaultElementNamespaceURI);
  			this.elementTypeInfosMap[elementTypeInfo.elementName.key] = elementTypeInfo.typeInfo;
  		}
  	},
  	buildStructureElements : function(context, structure) {
  		for (var index = 0; index < this.elementTypeInfos.length; index++) {
  			var elementTypeInfo = this.elementTypeInfos[index];
  			this.buildStructureElementTypeInfos(context, structure, elementTypeInfo);
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.ElementRefsPropertyInfo'
  });
  Jsonix.Model.ElementRefsPropertyInfo.Simplified = Jsonix.Class(Jsonix.Model.ElementRefsPropertyInfo, Jsonix.Binding.Unmarshalls.Element.AsSimplifiedElementRef, {
  	CLASS_NAME : 'Jsonix.Model.ElementRefsPropertyInfo.Simplified'
  });
  
  Jsonix.Model.AnyElementPropertyInfo = Jsonix.Class(Jsonix.Binding.Marshalls.Element, Jsonix.Binding.Marshalls.Element.AsElementRef, Jsonix.Binding.Unmarshalls.Element, Jsonix.Binding.Unmarshalls.Element.AsElementRef, Jsonix.Model.PropertyInfo, {
  	allowDom : true,
  	allowTypedObject : true,
  	mixed : true,
  	initialize : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		Jsonix.Model.PropertyInfo.prototype.initialize.apply(this, [ mapping ]);
  		var dom = Jsonix.Util.Type.defaultValue(mapping.allowDom, mapping.dom, true);
  		var typed = Jsonix.Util.Type.defaultValue(mapping.allowTypedObject, mapping.typed, true);
  		var mx = Jsonix.Util.Type.defaultValue(mapping.mixed, mapping.mx, true);
  		this.allowDom = dom;
  		this.allowTypedObject = typed;
  		this.mixed = mx;
  	},
  	unmarshal : function(context, input, scope) {
  		var result = null;
  		var that = this;
  		var callback = function(value) {
  			if (that.collection) {
  				if (result === null) {
  					result = [];
  				}
  				result.push(value);
  
  			} else {
  				if (result === null) {
  					result = value;
  				} else {
  					// TODO Report validation error
  					throw new Error("Value already set.");
  				}
  			}
  		};
  
  		var et = input.eventType;
  		if (et === Jsonix.XML.Input.START_ELEMENT) {
  			this.unmarshalElement(context, input, scope, callback);
  		} else if (this.mixed && (et === Jsonix.XML.Input.CHARACTERS || et === Jsonix.XML.Input.CDATA || et === Jsonix.XML.Input.ENTITY_REFERENCE)) {
  			callback(input.getText());
  		} else if (this.mixed && (et === Jsonix.XML.Input.SPACE)) {
  			// Whitespace
  			// return null;
  		} else if (et === Jsonix.XML.Input.COMMENT || et === Jsonix.XML.Input.PROCESSING_INSTRUCTION) {
  			// return null;
  		} else {
  			// TODO better exception
  			throw new Error("Illegal state: unexpected event type [" + et + "].");
  		}
  
  		return result;
  	},
  	marshal : function(value, context, output, scope) {
  		if (!Jsonix.Util.Type.exists(value)) {
  			return;
  		}
  		if (!this.collection) {
  			this.marshalItem(value, context, output, scope);
  		} else {
  			Jsonix.Util.Ensure.ensureArray(value);
  			for (var index = 0; index < value.length; index++) {
  				this.marshalItem(value[index], context, output, scope);
  			}
  		}
  	},
  	marshalItem : function(value, context, output, scope) {
  		if (this.mixed && Jsonix.Util.Type.isString(value)) {
  			// Mixed
  			output.writeCharacters(value);
  		} else if (this.allowDom && Jsonix.Util.Type.exists(value.nodeType)) {
  			// DOM node
  			output.writeNode(value);
  
  		} else {
  			if (this.allowTypedObject) {
  				this.marshalElement(value, context, output, scope);
  			}
  		}
  	},
  	doBuild : function(context, module) {
  		// Nothing to do
  	},
  	buildStructure : function(context, structure) {
  		Jsonix.Util.Ensure.ensureObject(structure);
  		if (Jsonix.Util.Type.exists(structure.value)) {
  			// TODO better exception
  			throw new Error("The structure already defines a value property.");
  		} else if (!Jsonix.Util.Type.exists(structure.elements)) {
  			structure.elements = {};
  		}
  
  		if ((this.allowDom || this.allowTypedObject)) {
  			// if (Jsonix.Util.Type.exists(structure.any)) {
  			// // TODO better exception
  			// throw new Error("The structure already defines the any
  			// property.");
  			// } else
  			// {
  			structure.any = this;
  			// }
  		}
  		if (this.mixed) {
  			// if (Jsonix.Util.Type.exists(structure.mixed)) {
  			// // TODO better exception
  			// throw new Error("The structure already defines the mixed
  			// property.");
  			// } else
  			// {
  			structure.mixed = this;
  			// }
  		}
  	},
  	CLASS_NAME : 'Jsonix.Model.AnyElementPropertyInfo'
  });
  Jsonix.Model.AnyElementPropertyInfo.Simplified = Jsonix.Class(Jsonix.Model.AnyElementPropertyInfo, Jsonix.Binding.Unmarshalls.Element.AsSimplifiedElementRef, {
  	CLASS_NAME : 'Jsonix.Model.AnyElementPropertyInfo.Simplified'
  });
  Jsonix.Model.Module = Jsonix.Class(Jsonix.Mapping.Styled, {
  	name : null,
  	typeInfos : null,
  	elementInfos : null,
  	targetNamespace : '',
  	defaultElementNamespaceURI : '',
  	defaultAttributeNamespaceURI : '',
  	initialize : function(mapping, options) {
  		Jsonix.Mapping.Styled.prototype.initialize.apply(this, [ options ]);
  		this.typeInfos = [];
  		this.elementInfos = [];
  		if (typeof mapping !== 'undefined') {
  			Jsonix.Util.Ensure.ensureObject(mapping);
  			var n = mapping.name || mapping.n || null;
  			this.name = n;
  			var dens = mapping.defaultElementNamespaceURI || mapping.dens || mapping.targetNamespace || mapping.tns || '';
  			this.defaultElementNamespaceURI = dens;
  			var tns = mapping.targetNamespace || mapping.tns || mapping.defaultElementNamespaceURI || mapping.dens || this.defaultElementNamespaceURI;
  			this.targetNamespace = tns;
  			var dans = mapping.defaultAttributeNamespaceURI || mapping.dans || '';
  			this.defaultAttributeNamespaceURI = dans;
  			// Initialize type infos
  			var tis = mapping.typeInfos || mapping.tis || [];
  			this.initializeTypeInfos(tis);
  
  			// Backwards compatibility: class infos can also be defined
  			// as properties of the schema, for instance Schema.MyType
  			for ( var typeInfoName in mapping) {
  				if (mapping.hasOwnProperty(typeInfoName)) {
  					if (mapping[typeInfoName] instanceof this.mappingStyle.classInfo) {
  						this.typeInfos.push(mapping[typeInfoName]);
  					}
  				}
  			}
  			var eis = mapping.elementInfos || mapping.eis || [];
  			// Initialize element infos
  			this.initializeElementInfos(eis);
  		}
  	},
  	initializeTypeInfos : function(typeInfoMappings) {
  		Jsonix.Util.Ensure.ensureArray(typeInfoMappings);
  		var index, typeInfoMapping, typeInfo;
  		for (index = 0; index < typeInfoMappings.length; index++) {
  			typeInfoMapping = typeInfoMappings[index];
  			typeInfo = this.createTypeInfo(typeInfoMapping);
  			this.typeInfos.push(typeInfo);
  		}
  	},
  	initializeElementInfos : function(elementInfoMappings) {
  		Jsonix.Util.Ensure.ensureArray(elementInfoMappings);
  		var index, elementInfoMapping, elementInfo;
  		for (index = 0; index < elementInfoMappings.length; index++) {
  			elementInfoMapping = elementInfoMappings[index];
  			elementInfo = this.createElementInfo(elementInfoMapping);
  			this.elementInfos.push(elementInfo);
  		}
  	},
  	createTypeInfo : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		var typeInfo;
  		// If mapping is already a type info, do nothing
  		if (mapping instanceof Jsonix.Model.TypeInfo) {
  			typeInfo = mapping;
  		}
  		// Else create it via generic mapping configuration
  		else {
  			mapping = Jsonix.Util.Type.cloneObject(mapping);
  			var type = mapping.type || mapping.t || 'classInfo';
  			// Locate the creator function
  			if (Jsonix.Util.Type.isFunction(this.typeInfoCreators[type])) {
  				var typeInfoCreator = this.typeInfoCreators[type];
  				// Call the creator function
  				typeInfo = typeInfoCreator.call(this, mapping);
  			} else {
  				throw new Error("Unknown type info type [" + type + "].");
  			}
  		}
  		return typeInfo;
  	},
  	initializeNames : function(mapping) {
  		var ln = mapping.localName || mapping.ln || null;
  		mapping.localName = ln;
  		var n = mapping.name || mapping.n || null;
  		mapping.name = n;
  		// Calculate both name as well as localName
  		// name is provided
  		if (Jsonix.Util.Type.isString(mapping.name)) {
  			// Obsolete code below
  			// // localName is not provided
  			// if (!Jsonix.Util.Type.isString(mapping.localName)) {
  			// // But module name is provided
  			// if (Jsonix.Util.Type.isString(this.name)) {
  			// // If name starts with module name, use second part
  			// // as local name
  			// if (mapping.name.indexOf(this.name + '.') === 0) {
  			// mapping.localName = mapping.name
  			// .substring(this.name.length + 1);
  			// }
  			// // Else use name as local name
  			// else {
  			// mapping.localName = mapping.name;
  			// }
  			// }
  			// // Module name is not provided, use name as local name
  			// else {
  			// mapping.localName = mapping.name;
  			// }
  			// }
  			if (mapping.name.length > 0 && mapping.name.charAt(0) === '.' && Jsonix.Util.Type.isString(this.name)) {
  				mapping.name = this.name + mapping.name;
  			}
  		}
  		// name is not provided but local name is provided
  		else if (Jsonix.Util.Type.isString(ln)) {
  			// Module name is provided
  			if (Jsonix.Util.Type.isString(this.name)) {
  				mapping.name = this.name + '.' + ln;
  			}
  			// Module name is not provided
  			else {
  				mapping.name = ln;
  			}
  		} else {
  			throw new Error("Neither [name/n] nor [localName/ln] was provided for the class info.");
  		}
  	},
  	createClassInfo : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		var dens = mapping.defaultElementNamespaceURI || mapping.dens || this.defaultElementNamespaceURI;
  		mapping.defaultElementNamespaceURI = dens;
  		var tns = mapping.targetNamespace || mapping.tns || this.targetNamespace;
  		mapping.targetNamespace = tns;
  		var dans = mapping.defaultAttributeNamespaceURI || mapping.dans || this.defaultAttributeNamespaceURI;
  		mapping.defaultAttributeNamespaceURI = dans;
  		this.initializeNames(mapping);
  		// Now both name an local name are initialized
  		var classInfo = new this.mappingStyle.classInfo(mapping, {
  			mappingStyle : this.mappingStyle
  		});
  		classInfo.module = this;
  		return classInfo;
  	},
  	createEnumLeafInfo : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		this.initializeNames(mapping);
  		// Now both name an local name are initialized
  		var enumLeafInfo = new this.mappingStyle.enumLeafInfo(mapping, {
  			mappingStyle : this.mappingStyle
  		});
  		enumLeafInfo.module = this;
  		return enumLeafInfo;
  	},
  	createList : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		var ti = mapping.baseTypeInfo || mapping.typeInfo || mapping.bti || mapping.ti || 'String';
  		var tn = mapping.typeName || mapping.tn || null;
  
  		if (Jsonix.Util.Type.exists(tn)) {
  			if (Jsonix.Util.Type.isString(tn)) {
  				tn = new Jsonix.XML.QName(this.targetNamespace, tn);
  			} else {
  				tn = Jsonix.XML.QName.fromObject(tn);
  			}
  		}
  		var s = mapping.separator || mapping.sep || ' ';
  		Jsonix.Util.Ensure.ensureExists(ti);
  		var listTypeInfo = new Jsonix.Schema.XSD.List(ti, tn, s);
  		listTypeInfo.module = this;
  		return listTypeInfo;
  	},
  	createElementInfo : function(mapping) {
  		Jsonix.Util.Ensure.ensureObject(mapping);
  		mapping = Jsonix.Util.Type.cloneObject(mapping);
  
  		var dens = mapping.defaultElementNamespaceURI || mapping.dens || this.defaultElementNamespaceURI;
  		mapping.defaultElementNamespaceURI = dens;
  		var en = mapping.elementName || mapping.en || undefined;
  		Jsonix.Util.Ensure.ensureExists(en);
  
  		var ti = mapping.typeInfo || mapping.ti || 'String';
  		Jsonix.Util.Ensure.ensureExists(ti);
  
  		mapping.typeInfo = ti;
  		if (Jsonix.Util.Type.isObject(en)) {
  			mapping.elementName = Jsonix.XML.QName.fromObject(en);
  		} else if (Jsonix.Util.Type.isString(en)) {
  			mapping.elementName = new Jsonix.XML.QName(this.defaultElementNamespaceURI, en);
  		} else {
  			throw new Error('Element info [' + mapping + '] must provide an element name.');
  		}
  
  		var sh = mapping.substitutionHead || mapping.sh || null;
  		if (Jsonix.Util.Type.exists(sh)) {
  			if (Jsonix.Util.Type.isObject(sh)) {
  				mapping.substitutionHead = Jsonix.XML.QName.fromObject(sh);
  			} else {
  				Jsonix.Util.Ensure.ensureString(sh);
  				mapping.substitutionHead = new Jsonix.XML.QName(this.defaultElementNamespaceURI, sh);
  			}
  		}
  
  		var elementInfo = new this.mappingStyle.elementInfo(mapping, {
  			mappingStyle : this.mappingStyle
  		});
  		elementInfo.module = this;
  		return elementInfo;
  	},
  	registerTypeInfos : function(context) {
  		for (var index = 0; index < this.typeInfos.length; index++) {
  			var typeInfo = this.typeInfos[index];
  			context.registerTypeInfo(typeInfo, this);
  		}
  	},
  	buildTypeInfos : function(context) {
  		for (var index = 0; index < this.typeInfos.length; index++) {
  			var typeInfo = this.typeInfos[index];
  			typeInfo.build(context, this);
  		}
  	},
  	registerElementInfos : function(context) {
  		for (var index = 0; index < this.elementInfos.length; index++) {
  			var elementInfo = this.elementInfos[index];
  			context.registerElementInfo(elementInfo, this);
  		}
  	},
  	buildElementInfos : function(context) {
  		for (var index = 0; index < this.elementInfos.length; index++) {
  			var elementInfo = this.elementInfos[index];
  			elementInfo.build(context, this);
  		}
  	},
  	// Obsolete, retained for backwards compatibility
  	cs : function() {
  		return this;
  	},
  	// Obsolete, retained for backwards compatibility
  	es : function() {
  		return this;
  	},
  	CLASS_NAME : 'Jsonix.Model.Module'
  });
  Jsonix.Model.Module.prototype.typeInfoCreators = {
  	"classInfo" : Jsonix.Model.Module.prototype.createClassInfo,
  	"c" : Jsonix.Model.Module.prototype.createClassInfo,
  	"enumInfo" : Jsonix.Model.Module.prototype.createEnumLeafInfo,
  	"enum" : Jsonix.Model.Module.prototype.createEnumLeafInfo,
  	"list" : Jsonix.Model.Module.prototype.createList,
  	"l" : Jsonix.Model.Module.prototype.createList
  };
  Jsonix.Mapping.Style.Standard = Jsonix.Class(Jsonix.Mapping.Style, {
  	marshaller : Jsonix.Binding.Marshaller,
  	unmarshaller : Jsonix.Binding.Unmarshaller,
  	module : Jsonix.Model.Module,
  	elementInfo : Jsonix.Model.ElementInfo,
  	classInfo : Jsonix.Model.ClassInfo,
  	enumLeafInfo : Jsonix.Model.EnumLeafInfo,
  	anyAttributePropertyInfo : Jsonix.Model.AnyAttributePropertyInfo,
  	anyElementPropertyInfo : Jsonix.Model.AnyElementPropertyInfo,
  	attributePropertyInfo : Jsonix.Model.AttributePropertyInfo,
  	elementMapPropertyInfo : Jsonix.Model.ElementMapPropertyInfo,
  	elementPropertyInfo : Jsonix.Model.ElementPropertyInfo,
  	elementsPropertyInfo : Jsonix.Model.ElementsPropertyInfo,
  	elementRefPropertyInfo : Jsonix.Model.ElementRefPropertyInfo,
  	elementRefsPropertyInfo : Jsonix.Model.ElementRefsPropertyInfo,
  	valuePropertyInfo : Jsonix.Model.ValuePropertyInfo,
  	initialize : function() {
  		Jsonix.Mapping.Style.prototype.initialize.apply(this);
  	},
  	CLASS_NAME : 'Jsonix.Mapping.Style.Standard'
  });
  Jsonix.Mapping.Style.STYLES.standard = new Jsonix.Mapping.Style.Standard();
  
  Jsonix.Mapping.Style.Simplified = Jsonix.Class(Jsonix.Mapping.Style, {
  	marshaller : Jsonix.Binding.Marshaller.Simplified,
  	unmarshaller : Jsonix.Binding.Unmarshaller.Simplified,
  	module : Jsonix.Model.Module,
  	elementInfo : Jsonix.Model.ElementInfo,
  	classInfo : Jsonix.Model.ClassInfo,
  	enumLeafInfo : Jsonix.Model.EnumLeafInfo,
  	anyAttributePropertyInfo : Jsonix.Model.AnyAttributePropertyInfo.Simplified,
  	anyElementPropertyInfo : Jsonix.Model.AnyElementPropertyInfo.Simplified,
  	attributePropertyInfo : Jsonix.Model.AttributePropertyInfo,
  	elementMapPropertyInfo : Jsonix.Model.ElementMapPropertyInfo,
  	elementPropertyInfo : Jsonix.Model.ElementPropertyInfo,
  	elementsPropertyInfo : Jsonix.Model.ElementsPropertyInfo,
  	elementRefPropertyInfo : Jsonix.Model.ElementRefPropertyInfo.Simplified,
  	elementRefsPropertyInfo : Jsonix.Model.ElementRefsPropertyInfo.Simplified,
  	valuePropertyInfo : Jsonix.Model.ValuePropertyInfo,
  	initialize : function() {
  		Jsonix.Mapping.Style.prototype.initialize.apply(this);
  	},
  	CLASS_NAME : 'Jsonix.Mapping.Style.Simplified'
  });
  Jsonix.Mapping.Style.STYLES.simplified = new Jsonix.Mapping.Style.Simplified();
  
  Jsonix.Schema.XSD = {};
  Jsonix.Schema.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';
  Jsonix.Schema.XSD.PREFIX = 'xsd';
  Jsonix.Schema.XSD.qname = function(localPart) {
  	Jsonix.Util.Ensure.ensureString(localPart);
  	return new Jsonix.XML.QName(Jsonix.Schema.XSD.NAMESPACE_URI, localPart,
  			Jsonix.Schema.XSD.PREFIX);
  };
  
  Jsonix.Schema.XSD.AnyType = Jsonix.Class(Jsonix.Model.ClassInfo, {
  	typeName : Jsonix.Schema.XSD.qname('anyType'),
  	initialize : function() {
  		Jsonix.Model.ClassInfo.prototype.initialize.call(this, {
  			name : 'AnyType',
  			propertyInfos : [ {
  				type : 'anyAttribute',
  				name : 'attributes'
  			}, {
  				type : 'anyElement',
  				name : 'content',
  				collection : true
  			} ]
  		});
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.AnyType'
  });
  Jsonix.Schema.XSD.AnyType.INSTANCE = new Jsonix.Schema.XSD.AnyType();
  Jsonix.Schema.XSD.AnySimpleType = Jsonix.Class(Jsonix.Model.TypeInfo, {
  	name : 'AnySimpleType',
  	typeName : Jsonix.Schema.XSD.qname('anySimpleType'),
  	initialize : function() {
  		Jsonix.Model.TypeInfo.prototype.initialize.apply(this, []);
  	},	
  	print : function(value, context, output, scope) {
  		return value;
  	},
  	parse : function(text, context, input, scope) {
  		return text;
  	},
  	isInstance : function(value, context, scope) {
  		return true;
  	},
  	reprint : function(value, context, output, scope) {
  		// Only reprint when the value is a string but not an instance
  		if (Jsonix.Util.Type.isString(value) && !this.isInstance(value, context, scope)) {
  			// Using null as input as input is not available
  			return this.print(this.parse(value, context, null, scope), context, output, scope);
  		}
  		else
  		{
  			return this.print(value, context, output, scope);
  		}
  	},
  	unmarshal : function(context, input, scope) {
  		var text = input.getElementText();
  		if (Jsonix.Util.StringUtils.isNotBlank(text)) {
  			return this.parse(text, context, input, scope);
  		}
  		else
  		{
  			return null;
  		}
  	},
  	marshal : function(value, context, output, scope) {
  		if (Jsonix.Util.Type.exists(value)) {
  			output.writeCharacters(this.reprint(value, context, output, scope));
  		}
  	},
  	build: function(context, module)
  	{
  		// Nothing to do
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.AnySimpleType'
  });
  Jsonix.Schema.XSD.AnySimpleType.INSTANCE = new Jsonix.Schema.XSD.AnySimpleType();
  Jsonix.Schema.XSD.List = Jsonix
  		.Class(
  				Jsonix.Schema.XSD.AnySimpleType,
  				{
  					name : null,
  					typeName : null,
  					typeInfo : null,
  					separator : ' ',
  					trimmedSeparator : Jsonix.Util.StringUtils.whitespaceCharacters,
  					simpleType : true,
  					built : false,
  					initialize : function(typeInfo, typeName, separator) {
  						Jsonix.Util.Ensure.ensureExists(typeInfo);
  						// TODO Ensure correct argument
  						this.typeInfo = typeInfo;
  						if (!Jsonix.Util.Type.exists(this.name)) {
  							this.name = typeInfo.name + "*";
  						}
  						if (Jsonix.Util.Type.exists(typeName)) {
  							// TODO Ensure correct argument
  							this.typeName = typeName;
  						}
  
  						if (Jsonix.Util.Type.isString(separator)) {
  							// TODO Ensure correct argument
  							this.separator = separator;
  						} else {
  							this.separator = ' ';
  						}
  
  						var trimmedSeparator = Jsonix.Util.StringUtils
  								.trim(this.separator);
  						if (trimmedSeparator.length === 0) {
  							this.trimmedSeparator = Jsonix.Util.StringUtils.whitespaceCharacters;
  						} else {
  							this.trimmedSeparator = trimmedSeparator;
  						}
  					},
  					build : function(context) {
  						if (!this.built) {
  							this.typeInfo = context.resolveTypeInfo(this.typeInfo, this.module);
  							this.built = true;
  						}
  					},
  					print : function(value, context, output, scope) {
  						if (!Jsonix.Util.Type.exists(value)) {
  							return null;
  						}
  						// TODO Exception if not an array
  						Jsonix.Util.Ensure.ensureArray(value);
  						var result = '';
  						for ( var index = 0; index < value.length; index++) {
  							if (index > 0) {
  								result = result + this.separator;
  							}
  							result = result + this.typeInfo.reprint(value[index], context, output, scope);
  						}
  						return result;
  					},
  					parse : function(text, context, input, scope) {
  						Jsonix.Util.Ensure.ensureString(text);
  						var items = Jsonix.Util.StringUtils
  								.splitBySeparatorChars(text,
  										this.trimmedSeparator);
  						var result = [];
  						for ( var index = 0; index < items.length; index++) {
  							result.push(this.typeInfo
  									.parse(Jsonix.Util.StringUtils.trim(items[index]), context, input, scope));
  						}
  						return result;
  					},
  					// TODO isInstance?
  					CLASS_NAME : 'Jsonix.Schema.XSD.List'
  				});
  
  Jsonix.Schema.XSD.String = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'String',
  	typeName : Jsonix.Schema.XSD.qname('string'),
  	unmarshal : function(context, input, scope) {
  		var text = input.getElementText();
  		return this.parse(text, context, input, scope);
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureString(value);
  		return value;
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		return text;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isString(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.String'
  });
  Jsonix.Schema.XSD.String.INSTANCE = new Jsonix.Schema.XSD.String();
  Jsonix.Schema.XSD.String.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.String.INSTANCE);
  Jsonix.Schema.XSD.Strings = Jsonix.Class(Jsonix.Schema.XSD.List, {
  	name : 'Strings',
  	initialize : function() {
  		Jsonix.Schema.XSD.List.prototype.initialize.apply(this, [ Jsonix.Schema.XSD.String.INSTANCE, Jsonix.Schema.XSD.qname('strings'), ' ' ]);
  	},
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.Strings'
  });
  Jsonix.Schema.XSD.Strings.INSTANCE = new Jsonix.Schema.XSD.Strings();
  Jsonix.Schema.XSD.NormalizedString = Jsonix.Class(Jsonix.Schema.XSD.String, {
  	name : 'NormalizedString',
  	typeName : Jsonix.Schema.XSD.qname('normalizedString'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.NormalizedString'
  });
  Jsonix.Schema.XSD.NormalizedString.INSTANCE = new Jsonix.Schema.XSD.NormalizedString();
  Jsonix.Schema.XSD.NormalizedString.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.NormalizedString.INSTANCE);
  Jsonix.Schema.XSD.Token = Jsonix.Class(Jsonix.Schema.XSD.NormalizedString, {
  	name : 'Token',
  	typeName : Jsonix.Schema.XSD.qname('token'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.Token'
  });
  Jsonix.Schema.XSD.Token.INSTANCE = new Jsonix.Schema.XSD.Token();
  Jsonix.Schema.XSD.Token.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Token.INSTANCE);
  Jsonix.Schema.XSD.Language = Jsonix.Class(Jsonix.Schema.XSD.Token, {
  	name : 'Language',
  	typeName : Jsonix.Schema.XSD.qname('language'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.Language'
  });
  Jsonix.Schema.XSD.Language.INSTANCE = new Jsonix.Schema.XSD.Language();
  Jsonix.Schema.XSD.Language.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Language.INSTANCE);
  Jsonix.Schema.XSD.Name = Jsonix.Class(Jsonix.Schema.XSD.Token, {
  	name : 'Name',
  	typeName : Jsonix.Schema.XSD.qname('Name'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.Name'
  });
  Jsonix.Schema.XSD.Name.INSTANCE = new Jsonix.Schema.XSD.Name();
  Jsonix.Schema.XSD.Name.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Name.INSTANCE);
  Jsonix.Schema.XSD.NCName = Jsonix.Class(Jsonix.Schema.XSD.Name, {
  	name : 'NCName',
  	typeName : Jsonix.Schema.XSD.qname('NCName'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.NCName'
  });
  Jsonix.Schema.XSD.NCName.INSTANCE = new Jsonix.Schema.XSD.NCName();
  Jsonix.Schema.XSD.NCName.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.NCName.INSTANCE);
  Jsonix.Schema.XSD.NMToken = Jsonix.Class(Jsonix.Schema.XSD.Token, {
  	name : 'NMToken',
  	typeName : Jsonix.Schema.XSD.qname('NMTOKEN'),
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.NMToken'
  });
  Jsonix.Schema.XSD.NMToken.INSTANCE = new Jsonix.Schema.XSD.NMToken();
  Jsonix.Schema.XSD.NMTokens = Jsonix.Class(Jsonix.Schema.XSD.List, {
  	name : 'NMTokens',
  	initialize : function() {
  		Jsonix.Schema.XSD.List.prototype.initialize.apply(this, [ Jsonix.Schema.XSD.NMToken.INSTANCE, Jsonix.Schema.XSD.qname('NMTOKEN'), ' ' ]);
  	},
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.NMTokens'
  });
  Jsonix.Schema.XSD.NMTokens.INSTANCE = new Jsonix.Schema.XSD.NMTokens();
  Jsonix.Schema.XSD.Boolean = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Boolean',
  	typeName : Jsonix.Schema.XSD.qname('boolean'),
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureBoolean(value);
  		return value ? 'true' : 'false';
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		if (text === 'true' || text === '1') {
  			return true;
  		} else if (text === 'false' || text === '0') {
  			return false;
  		} else {
  			throw new Error("Either [true], [1], [0] or [false] expected as boolean value.");
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isBoolean(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Boolean'
  });
  Jsonix.Schema.XSD.Boolean.INSTANCE = new Jsonix.Schema.XSD.Boolean();
  Jsonix.Schema.XSD.Boolean.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Boolean.INSTANCE);
  Jsonix.Schema.XSD.Base64Binary = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Base64Binary',
  	typeName : Jsonix.Schema.XSD.qname('base64Binary'),
  	charToByte : {},
  	byteToChar : [],
  	initialize : function() {
  		Jsonix.Schema.XSD.AnySimpleType.prototype.initialize.apply(this);
  		// Initialize charToByte and byteToChar table for fast
  		// lookups
  		var charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  		for (var i = 0; i < charTable.length; i++) {
  			var _char = charTable.charAt(i);
  			var _byte = charTable.charCodeAt(i);
  			this.byteToChar[i] = _char;
  			this.charToByte[_char] = i;
  		}
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureArray(value);
  		return this.encode(value);
  	},
  
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		return this.decode(text);
  	},
  	encode : function(uarray) {
  		var output = "";
  		var byte0;
  		var byte1;
  		var byte2;
  		var char0;
  		var char1;
  		var char2;
  		var char3;
  		var i = 0;
  		var j = 0;
  		var length = uarray.length;
  
  		for (i = 0; i < length; i += 3) {
  			byte0 = uarray[i] & 0xFF;
  			char0 = this.byteToChar[byte0 >> 2];
  
  			if (i + 1 < length) {
  				byte1 = uarray[i + 1] & 0xFF;
  				char1 = this.byteToChar[((byte0 & 0x03) << 4) | (byte1 >> 4)];
  				if (i + 2 < length) {
  					byte2 = uarray[i + 2] & 0xFF;
  					char2 = this.byteToChar[((byte1 & 0x0F) << 2) | (byte2 >> 6)];
  					char3 = this.byteToChar[byte2 & 0x3F];
  				} else {
  					char2 = this.byteToChar[(byte1 & 0x0F) << 2];
  					char3 = "=";
  				}
  			} else {
  				char1 = this.byteToChar[(byte0 & 0x03) << 4];
  				char2 = "=";
  				char3 = "=";
  			}
  			output = output + char0 + char1 + char2 + char3;
  		}
  		return output;
  	},
  	decode : function(text) {
  
  		input = text.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  
  		var length = (input.length / 4) * 3;
  		if (input.charAt(input.length - 1) === "=") {
  			length--;
  		}
  		if (input.charAt(input.length - 2) === "=") {
  			length--;
  		}
  
  		var uarray = new Array(length);
  
  		var byte0;
  		var byte1;
  		var byte2;
  		var char0;
  		var char1;
  		var char2;
  		var char3;
  		var i = 0;
  		var j = 0;
  
  		for (i = 0; i < length; i += 3) {
  			// get the 3 octects in 4 ascii chars
  			char0 = this.charToByte[input.charAt(j++)];
  			char1 = this.charToByte[input.charAt(j++)];
  			char2 = this.charToByte[input.charAt(j++)];
  			char3 = this.charToByte[input.charAt(j++)];
  
  			byte0 = (char0 << 2) | (char1 >> 4);
  			byte1 = ((char1 & 0x0F) << 4) | (char2 >> 2);
  			byte2 = ((char2 & 0x03) << 6) | char3;
  
  			uarray[i] = byte0;
  			if (char2 != 64) {
  				uarray[i + 1] = byte1;
  			}
  			if (char3 != 64) {
  				uarray[i + 2] = byte2;
  			}
  		}
  		return uarray;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isArray(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Base64Binary'
  });
  Jsonix.Schema.XSD.Base64Binary.INSTANCE = new Jsonix.Schema.XSD.Base64Binary();
  Jsonix.Schema.XSD.Base64Binary.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Base64Binary.INSTANCE);
  Jsonix.Schema.XSD.HexBinary = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'HexBinary',
  	typeName : Jsonix.Schema.XSD.qname('hexBinary'),
  	charToQuartet : {},
  	byteToDuplet : [],
  	initialize : function() {
  		Jsonix.Schema.XSD.AnySimpleType.prototype.initialize.apply(this);
  		var charTableUpperCase = "0123456789ABCDEF";
  		var charTableLowerCase = charTableUpperCase.toLowerCase();
  		var i;
  		for (i = 0; i < 16; i++) {
  			this.charToQuartet[charTableUpperCase.charAt(i)] = i;
  			if (i >= 0xA) {
  				this.charToQuartet[charTableLowerCase.charAt(i)] = i;
  			}
  		}
  		for (i = 0; i < 256; i++) {
  			this.byteToDuplet[i] =
  			//
  			charTableUpperCase[i >> 4] + charTableUpperCase[i & 0xF];
  		}
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureArray(value);
  		return this.encode(value);
  	},
  
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		return this.decode(text);
  	},
  	encode : function(uarray) {
  		var output = "";
  		for ( var i = 0; i < uarray.length; i++) {
  			output = output + this.byteToDuplet[uarray[i] & 0xFF];
  		}
  		return output;
  	},
  	decode : function(text) {
  		var input = text.replace(/[^A-Fa-f0-9]/g, "");
  		// Round by two
  		var length = input.length >> 1;
  		var uarray = new Array(length);
  		for ( var i = 0; i < length; i++) {
  			var char0 = input.charAt(2 * i);
  			var char1 = input.charAt(2 * i + 1);
  			uarray[i] = this.charToQuartet[char0] << 4
  					| this.charToQuartet[char1];
  		}
  		return uarray;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isArray(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.HexBinary'
  });
  Jsonix.Schema.XSD.HexBinary.INSTANCE = new Jsonix.Schema.XSD.HexBinary();
  Jsonix.Schema.XSD.HexBinary.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.HexBinary.INSTANCE);
  Jsonix.Schema.XSD.Number = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Number',
  	typeName : Jsonix.Schema.XSD.qname('number'),
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureNumberOrNaN(value);
  		if (Jsonix.Util.Type.isNaN(value)) {
  			return 'NaN';
  		} else if (value === Infinity) {
  			return 'INF';
  		} else if (value === -Infinity) {
  			return '-INF';
  		} else {
  			var text = String(value);
  			return text;
  		}
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		if (text === '-INF') {
  			return -Infinity;
  		} else if (text === 'INF') {
  			return Infinity;
  		} else if (text === 'NaN') {
  			return NaN;
  		} else {
  			var value = Number(text);
  			Jsonix.Util.Ensure.ensureNumber(value);
  			return value;
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isNumberOrNaN(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Number'
  });
  Jsonix.Schema.XSD.Number.INSTANCE = new Jsonix.Schema.XSD.Number();
  Jsonix.Schema.XSD.Number.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Number.INSTANCE);
  Jsonix.Schema.XSD.Float = Jsonix.Class(Jsonix.Schema.XSD.Number, {
  	name : 'Float',
  	typeName : Jsonix.Schema.XSD.qname('float'),
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isNaN(value) || value === -Infinity || value === Infinity || (Jsonix.Util.Type.isNumber(value) && value >= this.MIN_VALUE && value <= this.MAX_VALUE);
  	},
  	MIN_VALUE : -3.4028235e+38,
  	MAX_VALUE : 3.4028235e+38,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Float'
  });
  Jsonix.Schema.XSD.Float.INSTANCE = new Jsonix.Schema.XSD.Float();
  Jsonix.Schema.XSD.Float.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Float.INSTANCE);
  Jsonix.Schema.XSD.Decimal = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Decimal',
  	typeName : Jsonix.Schema.XSD.qname('decimal'),
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureNumber(value);
  		var text = String(value);
  		return text;
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var value = Number(text);
  		Jsonix.Util.Ensure.ensureNumber(value);
  		return value;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isNumber(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Decimal'
  });
  Jsonix.Schema.XSD.Decimal.INSTANCE = new Jsonix.Schema.XSD.Decimal();
  Jsonix.Schema.XSD.Decimal.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Decimal.INSTANCE);
  Jsonix.Schema.XSD.Integer = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Integer',
  	typeName : Jsonix.Schema.XSD.qname('integer'),
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureInteger(value);
  		var text = String(value);
  		return text;
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var value = Number(text);
  		Jsonix.Util.Ensure.ensureInteger(value);
  		return value;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.NumberUtils.isInteger(value) && value >= this.MIN_VALUE && value <= this.MAX_VALUE;
  	},
  	MIN_VALUE : -9223372036854775808,
  	MAX_VALUE : 9223372036854775807,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Integer'
  });
  Jsonix.Schema.XSD.Integer.INSTANCE = new Jsonix.Schema.XSD.Integer();
  Jsonix.Schema.XSD.Integer.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Integer.INSTANCE);
  Jsonix.Schema.XSD.NonPositiveInteger = Jsonix.Class(Jsonix.Schema.XSD.Integer, {
  	name : 'NonPositiveInteger',
  	typeName : Jsonix.Schema.XSD.qname('nonPositiveInteger'),
  	MIN_VALUE: -9223372036854775808,
  	MAX_VALUE: 0,
  	CLASS_NAME : 'Jsonix.Schema.XSD.NonPositiveInteger'
  });
  Jsonix.Schema.XSD.NonPositiveInteger.INSTANCE = new Jsonix.Schema.XSD.NonPositiveInteger();
  Jsonix.Schema.XSD.NonPositiveInteger.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.NonPositiveInteger.INSTANCE);
  Jsonix.Schema.XSD.NegativeInteger = Jsonix.Class(Jsonix.Schema.XSD.NonPositiveInteger, {
  	name : 'NegativeInteger',
  	typeName : Jsonix.Schema.XSD.qname('negativeInteger'),
  	MIN_VALUE: -9223372036854775808,
  	MAX_VALUE: -1,
  	CLASS_NAME : 'Jsonix.Schema.XSD.NegativeInteger'
  });
  Jsonix.Schema.XSD.NegativeInteger.INSTANCE = new Jsonix.Schema.XSD.NegativeInteger();
  Jsonix.Schema.XSD.NegativeInteger.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.NegativeInteger.INSTANCE);
  Jsonix.Schema.XSD.Long = Jsonix.Class(Jsonix.Schema.XSD.Integer, {
  	name : 'Long',
  	typeName : Jsonix.Schema.XSD.qname('long'),
  	MIN_VALUE : -9223372036854775808,
  	MAX_VALUE : 9223372036854775807,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Long'
  });
  Jsonix.Schema.XSD.Long.INSTANCE = new Jsonix.Schema.XSD.Long();
  Jsonix.Schema.XSD.Long.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.Long.INSTANCE);
  Jsonix.Schema.XSD.Int = Jsonix.Class(Jsonix.Schema.XSD.Long, {
  	name : 'Int',
  	typeName : Jsonix.Schema.XSD.qname('int'),
  	MIN_VALUE : -2147483648,
  	MAX_VALUE : 2147483647,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Int'
  });
  Jsonix.Schema.XSD.Int.INSTANCE = new Jsonix.Schema.XSD.Int();
  Jsonix.Schema.XSD.Int.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.Int.INSTANCE);
  Jsonix.Schema.XSD.Short = Jsonix.Class(Jsonix.Schema.XSD.Int, {
  	name : 'Short',
  	typeName : Jsonix.Schema.XSD.qname('short'),
  	MIN_VALUE : -32768,
  	MAX_VALUE : 32767,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Short'
  });
  Jsonix.Schema.XSD.Short.INSTANCE = new Jsonix.Schema.XSD.Short();
  Jsonix.Schema.XSD.Short.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Short.INSTANCE);
  Jsonix.Schema.XSD.Byte = Jsonix.Class(Jsonix.Schema.XSD.Short, {
  	name : 'Byte',
  	typeName : Jsonix.Schema.XSD.qname('byte'),
  	MIN_VALUE : -128,
  	MAX_VALUE : 127,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Byte'
  });
  Jsonix.Schema.XSD.Byte.INSTANCE = new Jsonix.Schema.XSD.Byte();
  Jsonix.Schema.XSD.Byte.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Byte.INSTANCE);
  Jsonix.Schema.XSD.NonNegativeInteger = Jsonix.Class(Jsonix.Schema.XSD.Integer, {
  	name : 'NonNegativeInteger',
  	typeName : Jsonix.Schema.XSD.qname('nonNegativeInteger'),
  	MIN_VALUE: 0,
  	MAX_VALUE: 9223372036854775807,
  	CLASS_NAME : 'Jsonix.Schema.XSD.NonNegativeInteger'
  });
  Jsonix.Schema.XSD.NonNegativeInteger.INSTANCE = new Jsonix.Schema.XSD.NonNegativeInteger();
  Jsonix.Schema.XSD.NonNegativeInteger.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.NonNegativeInteger.INSTANCE);
  Jsonix.Schema.XSD.UnsignedLong = Jsonix.Class(Jsonix.Schema.XSD.NonNegativeInteger, {
  	name : 'UnsignedLong',
  	typeName : Jsonix.Schema.XSD.qname('unsignedLong'),
  	MIN_VALUE : 0,
  	MAX_VALUE : 18446744073709551615,
  	CLASS_NAME : 'Jsonix.Schema.XSD.UnsignedLong'
  });
  Jsonix.Schema.XSD.UnsignedLong.INSTANCE = new Jsonix.Schema.XSD.UnsignedLong();
  Jsonix.Schema.XSD.UnsignedLong.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.UnsignedLong.INSTANCE);
  Jsonix.Schema.XSD.UnsignedInt = Jsonix.Class(Jsonix.Schema.XSD.UnsignedLong, {
  	name : 'UnsignedInt',
  	typeName : Jsonix.Schema.XSD.qname('unsignedInt'),
  	MIN_VALUE : 0,
  	MAX_VALUE : 4294967295,
  	CLASS_NAME : 'Jsonix.Schema.XSD.UnsignedInt'
  });
  Jsonix.Schema.XSD.UnsignedInt.INSTANCE = new Jsonix.Schema.XSD.UnsignedInt();
  Jsonix.Schema.XSD.UnsignedInt.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.UnsignedInt.INSTANCE);
  Jsonix.Schema.XSD.UnsignedShort = Jsonix.Class(Jsonix.Schema.XSD.UnsignedInt, {
  	name : 'UnsignedShort',
  	typeName : Jsonix.Schema.XSD.qname('unsignedShort'),
  	MIN_VALUE : 0,
  	MAX_VALUE : 65535,
  	CLASS_NAME : 'Jsonix.Schema.XSD.UnsignedShort'
  });
  Jsonix.Schema.XSD.UnsignedShort.INSTANCE = new Jsonix.Schema.XSD.UnsignedShort();
  Jsonix.Schema.XSD.UnsignedShort.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.UnsignedShort.INSTANCE);
  Jsonix.Schema.XSD.UnsignedByte = Jsonix.Class(Jsonix.Schema.XSD.UnsignedShort, {
  	name : 'UnsignedByte',
  	typeName : Jsonix.Schema.XSD.qname('unsignedByte'),
  	MIN_VALUE : 0,
  	MAX_VALUE : 255,
  	CLASS_NAME : 'Jsonix.Schema.XSD.UnsignedByte'
  });
  Jsonix.Schema.XSD.UnsignedByte.INSTANCE = new Jsonix.Schema.XSD.UnsignedByte();
  Jsonix.Schema.XSD.UnsignedByte.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.UnsignedByte.INSTANCE);
  Jsonix.Schema.XSD.PositiveInteger = Jsonix.Class(Jsonix.Schema.XSD.NonNegativeInteger, {
  	name : 'PositiveInteger',
  	typeName : Jsonix.Schema.XSD.qname('positiveInteger'),
  	MIN_VALUE : 1,
  	MAX_VALUE : 9223372036854775807,
  	CLASS_NAME : 'Jsonix.Schema.XSD.PositiveInteger'
  });
  Jsonix.Schema.XSD.PositiveInteger.INSTANCE = new Jsonix.Schema.XSD.PositiveInteger();
  Jsonix.Schema.XSD.PositiveInteger.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.PositiveInteger.INSTANCE);
  Jsonix.Schema.XSD.Double = Jsonix.Class(Jsonix.Schema.XSD.Number, {
  	name : 'Double',
  	typeName : Jsonix.Schema.XSD.qname('double'),
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isNaN(value) || value === -Infinity || value === Infinity || (Jsonix.Util.Type.isNumber(value) && value >= this.MIN_VALUE && value <= this.MAX_VALUE);
  	},
  	MIN_VALUE : -1.7976931348623157e+308,
  	MAX_VALUE : 1.7976931348623157e+308,
  	CLASS_NAME : 'Jsonix.Schema.XSD.Double'
  });
  Jsonix.Schema.XSD.Double.INSTANCE = new Jsonix.Schema.XSD.Double();
  Jsonix.Schema.XSD.Double.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Double.INSTANCE);
  Jsonix.Schema.XSD.AnyURI = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'AnyURI',
  	typeName : Jsonix.Schema.XSD.qname('anyURI'),
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureString(value);
  		return value;
  	},
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		return text;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isString(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.AnyURI'
  });
  Jsonix.Schema.XSD.AnyURI.INSTANCE = new Jsonix.Schema.XSD.AnyURI();
  Jsonix.Schema.XSD.AnyURI.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.AnyURI.INSTANCE);
  Jsonix.Schema.XSD.QName = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'QName',
  	typeName : Jsonix.Schema.XSD.qname('QName'),
  	print : function(value, context, output, scope) {
  		var qName = Jsonix.XML.QName.fromObject(value);
  		var prefix;
  		var localPart = qName.localPart;
  		if (output) {
  			// If QName does not provide the prefix, let it be generated
  			prefix = output.getPrefix(qName.namespaceURI, qName.prefix||null);
  			output.declareNamespace(qName.namespaceURI, prefix);
  		} else {
  			prefix = qName.prefix;
  		}
  		return !prefix ? localPart : (prefix + ':' + localPart);
  	},
  	parse : function(value, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(value);
  		value = Jsonix.Util.StringUtils.trim(value);
  		var prefix;
  		var localPart;
  		var colonPosition = value.indexOf(':');
  		if (colonPosition === -1) {
  			prefix = '';
  			localPart = value;
  		} else if (colonPosition > 0 && colonPosition < (value.length - 1)) {
  			prefix = value.substring(0, colonPosition);
  			localPart = value.substring(colonPosition + 1);
  		} else {
  			throw new Error('Invalid QName [' + value + '].');
  		}
  		var namespaceContext = input || context || null;
  		if (!namespaceContext)
  		{
  			return value;
  		}
  		else
  		{
  			var namespaceURI = namespaceContext.getNamespaceURI(prefix);
  			if (Jsonix.Util.Type.isString(namespaceURI))
  			{
  				return new Jsonix.XML.QName(namespaceURI, localPart, prefix);
  			}
  			else
  			{
  				throw new Error('Prefix [' + prefix + '] of the QName [' + value + '] is not bound in this context.');
  			}
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return (value instanceof Jsonix.XML.QName) || (Jsonix.Util.Type.isObject(value) && Jsonix.Util.Type.isString(value.localPart || value.lp));
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.QName'
  });
  Jsonix.Schema.XSD.QName.INSTANCE = new Jsonix.Schema.XSD.QName();
  Jsonix.Schema.XSD.QName.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.QName.INSTANCE);
  Jsonix.Schema.XSD.Calendar = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Calendar',
  	typeName : Jsonix.Schema.XSD.qname('calendar'),
  	parse : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.DATETIME_PATTERN + "$"))) {
  			return this.parseDateTime(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.DATE_PATTERN + "$"))) {
  			return this.parseDate(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.TIME_PATTERN + "$"))) {
  			return this.parseTime(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.GYEAR_MONTH_PATTERN + "$"))) {
  			return this.parseGYearMonth(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.GYEAR_PATTERN + "$"))) {
  			return this.parseGYear(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.GMONTH_DAY_PATTERN + "$"))) {
  			return this.parseGMonthDay(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.GMONTH_PATTERN + "$"))) {
  			return this.parseGMonth(text, context, input, scope);
  		} else if (text.match(new RegExp("^" + Jsonix.Schema.XSD.Calendar.GDAY_PATTERN + "$"))) {
  			return this.parseGDay(text, context, input, scope);
  		} else {
  			throw new Error('Value [' + text + '] does not match xs:dateTime, xs:date, xs:time, xs:gYearMonth, xs:gYear, xs:gMonthDay, xs:gMonth or xs:gDay patterns.');
  		}
  	},
  	parseGYearMonth : function(value, context, input, scope) {
  		var gYearMonthExpression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.GYEAR_MONTH_PATTERN + "$");
  		var results = value.match(gYearMonthExpression);
  		if (results !== null) {
  			var data = {
  				year : parseInt(results[1], 10),
  				month : parseInt(results[5], 10),
  				timezone : this.parseTimezoneString(results[7])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:gYearMonth pattern.');
  	},
  	parseGYear : function(value, context, input, scope) {
  		var gYearExpression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.GYEAR_PATTERN + "$");
  		var results = value.match(gYearExpression);
  		if (results !== null) {
  			var data = {
  				year : parseInt(results[1], 10),
  				timezone : this.parseTimezoneString(results[5])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:gYear pattern.');
  	},
  	parseGMonthDay : function(value, context, input, scope) {
  		var gMonthDayExpression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.GMONTH_DAY_PATTERN + "$");
  		var results = value.match(gMonthDayExpression);
  		if (results !== null) {
  			var data = {
  				month : parseInt(results[2], 10),
  				day : parseInt(results[3], 10),
  				timezone : this.parseTimezoneString(results[5])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:gMonthDay pattern.');
  	},
  	parseGMonth : function(value, context, input, scope) {
  		var gMonthExpression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.GMONTH_PATTERN + "$");
  		var results = value.match(gMonthExpression);
  		if (results !== null) {
  			var data = {
  				month : parseInt(results[2], 10),
  				timezone : this.parseTimezoneString(results[3])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:gMonth pattern.');
  	},
  	parseGDay : function(value, context, input, scope) {
  		var gDayExpression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.GDAY_PATTERN + "$");
  		var results = value.match(gDayExpression);
  		if (results !== null) {
  			var data = {
  				day : parseInt(results[2], 10),
  				timezone : this.parseTimezoneString(results[3])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:gDay pattern.');
  	},
  	parseDateTime : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var expression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.DATETIME_PATTERN + "$");
  		var results = text.match(expression);
  		if (results !== null) {
  			var data = {
  				year : parseInt(results[1], 10),
  				month : parseInt(results[5], 10),
  				day : parseInt(results[7], 10),
  				hour : parseInt(results[9], 10),
  				minute : parseInt(results[10], 10),
  				second : parseInt(results[11], 10),
  				fractionalSecond : (results[12] ? parseFloat(results[12]) : 0),
  				timezone : this.parseTimezoneString(results[14])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:date pattern.');
  	},
  	parseDate : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var expression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.DATE_PATTERN + "$");
  		var results = text.match(expression);
  		if (results !== null) {
  			var data = {
  				year : parseInt(results[1], 10),
  				month : parseInt(results[5], 10),
  				day : parseInt(results[7], 10),
  				timezone : this.parseTimezoneString(results[9])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:date pattern.');
  	},
  	parseTime : function(text, context, input, scope) {
  		Jsonix.Util.Ensure.ensureString(text);
  		var expression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.TIME_PATTERN + "$");
  		var results = text.match(expression);
  		if (results !== null) {
  			var data = {
  				hour : parseInt(results[1], 10),
  				minute : parseInt(results[2], 10),
  				second : parseInt(results[3], 10),
  				fractionalSecond : (results[4] ? parseFloat(results[4]) : 0),
  				timezone : this.parseTimezoneString(results[6])
  			};
  			return new Jsonix.XML.Calendar(data);
  		}
  		throw new Error('Value [' + value + '] does not match the xs:time pattern.');
  	},
  	parseTimezoneString : function(text) {
  		// (('+' | '-') hh ':' mm) | 'Z'
  		if (!Jsonix.Util.Type.isString(text)) {
  			return NaN;
  		} else if (text === '') {
  			return NaN;
  		} else if (text === 'Z') {
  			return 0;
  		} else if (text === '+14:00') {
  			return 14 * 60;
  		} else if (text === '-14:00') {
  			return -14 * 60;
  		} else {
  			var expression = new RegExp("^" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + "$");
  			var results = text.match(expression);
  			if (results !== null) {
  				var sign = results[1] === '+' ? 1 : -1;
  				var hour = parseInt(results[4], 10);
  				var minute = parseInt(results[5], 10);
  				return sign * (hour * 60 + minute);
  			}
  			throw new Error('Value [' + value + '] does not match the timezone pattern.');
  		}
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		if (Jsonix.Util.NumberUtils.isInteger(value.year) && Jsonix.Util.NumberUtils.isInteger(value.month) && Jsonix.Util.NumberUtils.isInteger(value.day) && Jsonix.Util.NumberUtils.isInteger(value.hour) && Jsonix.Util.NumberUtils.isInteger(value.minute) && Jsonix.Util.NumberUtils.isInteger(value.second)) {
  			return this.printDateTime(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.year) && Jsonix.Util.NumberUtils.isInteger(value.month) && Jsonix.Util.NumberUtils.isInteger(value.day)) {
  			return this.printDate(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.hour) && Jsonix.Util.NumberUtils.isInteger(value.minute) && Jsonix.Util.NumberUtils.isInteger(value.second)) {
  			return this.printTime(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.year) && Jsonix.Util.NumberUtils.isInteger(value.month)) {
  			return this.printGYearMonth(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.month) && Jsonix.Util.NumberUtils.isInteger(value.day)) {
  			return this.printGMonthDay(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.year)) {
  			return this.printGYear(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.month)) {
  			return this.printGMonth(value);
  		} else if (Jsonix.Util.NumberUtils.isInteger(value.day)) {
  			return this.printGDay(value);
  		} else {
  			throw new Error('Value [' + value + '] is not recognized as dateTime, date or time.');
  		}
  	},
  	printDateTime : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		Jsonix.Util.Ensure.ensureInteger(value.year);
  		Jsonix.Util.Ensure.ensureInteger(value.month);
  		Jsonix.Util.Ensure.ensureInteger(value.day);
  		Jsonix.Util.Ensure.ensureInteger(value.hour);
  		Jsonix.Util.Ensure.ensureInteger(value.minute);
  		Jsonix.Util.Ensure.ensureNumber(value.second);
  		if (Jsonix.Util.Type.exists(value.fractionalString)) {
  			Jsonix.Util.Ensure.ensureNumber(value.fractionalString);
  		}
  		if (Jsonix.Util.Type.exists(value.timezone) && !Jsonix.Util.Type.isNaN(value.timezone)) {
  			Jsonix.Util.Ensure.ensureInteger(value.timezone);
  		}
  		var result = this.printDateString(value);
  		result = result + 'T';
  		result = result + this.printTimeString(value);
  		if (Jsonix.Util.Type.exists(value.timezone)) {
  			result = result + this.printTimezoneString(value.timezone);
  		}
  		return result;
  	},
  	printDate : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		Jsonix.Util.Ensure.ensureNumber(value.year);
  		Jsonix.Util.Ensure.ensureNumber(value.month);
  		Jsonix.Util.Ensure.ensureNumber(value.day);
  		if (Jsonix.Util.Type.exists(value.timezone) && !Jsonix.Util.Type.isNaN(value.timezone)) {
  			Jsonix.Util.Ensure.ensureInteger(value.timezone);
  		}
  		var result = this.printDateString(value);
  		if (Jsonix.Util.Type.exists(value.timezone)) {
  			result = result + this.printTimezoneString(value.timezone);
  		}
  		return result;
  	},
  	printTime : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		Jsonix.Util.Ensure.ensureNumber(value.hour);
  		Jsonix.Util.Ensure.ensureNumber(value.minute);
  		Jsonix.Util.Ensure.ensureNumber(value.second);
  		if (Jsonix.Util.Type.exists(value.fractionalString)) {
  			Jsonix.Util.Ensure.ensureNumber(value.fractionalString);
  		}
  		if (Jsonix.Util.Type.exists(value.timezone) && !Jsonix.Util.Type.isNaN(value.timezone)) {
  			Jsonix.Util.Ensure.ensureInteger(value.timezone);
  		}
  
  		var result = this.printTimeString(value);
  		if (Jsonix.Util.Type.exists(value.timezone)) {
  			result = result + this.printTimezoneString(value.timezone);
  		}
  		return result;
  	},
  	printDateString : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		Jsonix.Util.Ensure.ensureInteger(value.year);
  		Jsonix.Util.Ensure.ensureInteger(value.month);
  		Jsonix.Util.Ensure.ensureInteger(value.day);
  		return (value.year < 0 ? ('-' + this.printYear(-value.year)) : this.printYear(value.year)) + '-' + this.printMonth(value.month) + '-' + this.printDay(value.day);
  	},
  	printTimeString : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		Jsonix.Util.Ensure.ensureInteger(value.hour);
  		Jsonix.Util.Ensure.ensureInteger(value.minute);
  		Jsonix.Util.Ensure.ensureInteger(value.second);
  		if (Jsonix.Util.Type.exists(value.fractionalSecond)) {
  			Jsonix.Util.Ensure.ensureNumber(value.fractionalSecond);
  		}
  		var result = this.printHour(value.hour);
  		result = result + ':';
  		result = result + this.printMinute(value.minute);
  		result = result + ':';
  		result = result + this.printSecond(value.second);
  		if (Jsonix.Util.Type.exists(value.fractionalSecond)) {
  			result = result + this.printFractionalSecond(value.fractionalSecond);
  		}
  		return result;
  	},
  	printTimezoneString : function(value) {
  		if (!Jsonix.Util.Type.exists(value) || Jsonix.Util.Type.isNaN(value)) {
  			return '';
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value);
  
  			var sign = value < 0 ? -1 : (value > 0 ? 1 : 0);
  			var data = value * sign;
  			var minute = data % 60;
  			var hour = Math.floor(data / 60);
  
  			var result;
  			if (sign === 0) {
  				return 'Z';
  			} else {
  				if (sign > 0) {
  					result = '+';
  				} else if (sign < 0) {
  					result = '-';
  				}
  				result = result + this.printHour(hour);
  				result = result + ':';
  				result = result + this.printMinute(minute);
  				return result;
  			}
  		}
  	},
  	printGDay : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var day = undefined;
  		var timezone = undefined;
  
  		if (value instanceof Date) {
  			day = value.getDate();
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value.day);
  			day = value.day;
  			timezone = value.timezone;
  		}
  		Jsonix.XML.Calendar.validateDay(day);
  		Jsonix.XML.Calendar.validateTimezone(timezone);
  		return "---" + this.printDay(day) + this.printTimezoneString(timezone);
  	},
  	printGMonth : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var month = undefined;
  		var timezone = undefined;
  
  		if (value instanceof Date) {
  			month = value.getMonth() + 1;
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value.month);
  			month = value.month;
  			timezone = value.timezone;
  		}
  		Jsonix.XML.Calendar.validateMonth(month);
  		Jsonix.XML.Calendar.validateTimezone(timezone);
  		return "--" + this.printMonth(month) + this.printTimezoneString(timezone);
  	},
  	printGMonthDay : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var month = undefined;
  		var day = undefined;
  		var timezone = undefined;
  
  		if (value instanceof Date) {
  			month = value.getMonth() + 1;
  			day = value.getDate();
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value.month);
  			Jsonix.Util.Ensure.ensureInteger(value.day);
  			month = value.month;
  			day = value.day;
  			timezone = value.timezone;
  		}
  		Jsonix.XML.Calendar.validateMonthDay(month, day);
  		Jsonix.XML.Calendar.validateTimezone(timezone);
  		return "--" + this.printMonth(month) + "-" + this.printDay(day) + this.printTimezoneString(timezone);
  	},
  	printGYear : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var year = undefined;
  		var timezone = undefined;
  
  		if (value instanceof Date) {
  			year = value.getFullYear();
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value.year);
  			year = value.year;
  			timezone = value.timezone;
  		}
  		Jsonix.XML.Calendar.validateYear(year);
  		Jsonix.XML.Calendar.validateTimezone(timezone);
  		return this.printSignedYear(year) + this.printTimezoneString(timezone);
  	},
  	printGYearMonth : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		var year = undefined;
  		var month = undefined;
  		var timezone = undefined;
  
  		if (value instanceof Date) {
  			year = value.getFullYear();
  			month = value.getMonth() + 1;
  		} else {
  			Jsonix.Util.Ensure.ensureInteger(value.year);
  			year = value.year;
  			month = value.month;
  			timezone = value.timezone;
  		}
  		Jsonix.XML.Calendar.validateYear(year);
  		Jsonix.XML.Calendar.validateMonth(month);
  		Jsonix.XML.Calendar.validateTimezone(timezone);
  		return this.printSignedYear(year) + "-" + this.printMonth(month) + this.printTimezoneString(timezone);
  	},
  	printSignedYear : function(value) {
  		return value < 0 ? ("-" + this.printYear(value * -1)) : (this.printYear(value));
  	},
  	printYear : function(value) {
  		return this.printInteger(value, 4);
  	},
  	printMonth : function(value) {
  		return this.printInteger(value, 2);
  	},
  	printDay : function(value) {
  		return this.printInteger(value, 2);
  	},
  	printHour : function(value) {
  		return this.printInteger(value, 2);
  	},
  	printMinute : function(value) {
  		return this.printInteger(value, 2);
  	},
  	printSecond : function(value) {
  		return this.printInteger(value, 2);
  	},
  	printFractionalSecond : function(value) {
  		Jsonix.Util.Ensure.ensureNumber(value);
  		if (value < 0 || value >= 1) {
  			throw new Error('Fractional second [' + value + '] must be between 0 and 1.');
  		} else if (value === 0) {
  			return '';
  		} else {
  			var string = String(value);
  			var dotIndex = string.indexOf('.');
  			if (dotIndex < 0) {
  				return '';
  			} else {
  				return string.substring(dotIndex);
  			}
  		}
  	},
  	printInteger : function(value, length) {
  		Jsonix.Util.Ensure.ensureInteger(value);
  		Jsonix.Util.Ensure.ensureInteger(length);
  		if (length <= 0) {
  			throw new Error('Length [' + value + '] must be positive.');
  		}
  		if (value < 0) {
  			throw new Error('Value [' + value + '] must not be negative.');
  		}
  		var result = String(value);
  		for (var i = result.length; i < length; i++) {
  			result = '0' + result;
  		}
  		return result;
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isObject(value) && ((Jsonix.Util.NumberUtils.isInteger(value.year) && Jsonix.Util.NumberUtils.isInteger(value.month) && Jsonix.Util.NumberUtils.isInteger(value.day)) || (Jsonix.Util.NumberUtils.isInteger(value.hour) && Jsonix.Util.NumberUtils.isInteger(value.minute) && Jsonix.Util.NumberUtils.isInteger(value.second)));
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Calendar'
  });
  
  Jsonix.Schema.XSD.Calendar.YEAR_PATTERN = "-?([1-9][0-9]*)?((?!(0000))[0-9]{4})";
  Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN = "Z|([\\-\\+])(((0[0-9]|1[0-3]):([0-5][0-9]))|(14:00))";
  Jsonix.Schema.XSD.Calendar.MONTH_PATTERN = "(0[1-9]|1[0-2])";
  Jsonix.Schema.XSD.Calendar.SINGLE_MONTH_PATTERN = "\\-\\-" + Jsonix.Schema.XSD.Calendar.MONTH_PATTERN;
  Jsonix.Schema.XSD.Calendar.DAY_PATTERN = "(0[1-9]|[12][0-9]|3[01])";
  Jsonix.Schema.XSD.Calendar.SINGLE_DAY_PATTERN = "\\-\\-\\-" + Jsonix.Schema.XSD.Calendar.DAY_PATTERN;
  Jsonix.Schema.XSD.Calendar.GYEAR_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.YEAR_PATTERN + ")" + "(" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ")?";
  Jsonix.Schema.XSD.Calendar.GMONTH_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.SINGLE_MONTH_PATTERN + ")" + "(" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ")?";
  Jsonix.Schema.XSD.Calendar.GDAY_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.SINGLE_DAY_PATTERN + ")" + "(" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ")?";
  Jsonix.Schema.XSD.Calendar.GYEAR_MONTH_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.YEAR_PATTERN + ")" + "-" + "(" + Jsonix.Schema.XSD.Calendar.DAY_PATTERN + ")" + "(" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ")?";
  Jsonix.Schema.XSD.Calendar.GMONTH_DAY_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.SINGLE_MONTH_PATTERN + ")" + "-" + "(" + Jsonix.Schema.XSD.Calendar.DAY_PATTERN + ")" + "(" + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ")?";
  Jsonix.Schema.XSD.Calendar.DATE_PART_PATTERN = "(" + Jsonix.Schema.XSD.Calendar.YEAR_PATTERN + ")" + "-" + "(" + Jsonix.Schema.XSD.Calendar.MONTH_PATTERN + ")" + "-" + "(" + Jsonix.Schema.XSD.Calendar.DAY_PATTERN + ")";
  Jsonix.Schema.XSD.Calendar.TIME_PART_PATTERN = "([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\\.([0-9]+))?";
  Jsonix.Schema.XSD.Calendar.TIME_PATTERN = Jsonix.Schema.XSD.Calendar.TIME_PART_PATTERN + '(' + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ')?';
  Jsonix.Schema.XSD.Calendar.DATE_PATTERN = Jsonix.Schema.XSD.Calendar.DATE_PART_PATTERN + '(' + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ')?';
  Jsonix.Schema.XSD.Calendar.DATETIME_PATTERN = Jsonix.Schema.XSD.Calendar.DATE_PART_PATTERN + 'T' + Jsonix.Schema.XSD.Calendar.TIME_PART_PATTERN + '(' + Jsonix.Schema.XSD.Calendar.TIMEZONE_PATTERN + ')?';
  Jsonix.Schema.XSD.Calendar.INSTANCE = new Jsonix.Schema.XSD.Calendar();
  Jsonix.Schema.XSD.Calendar.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Calendar.INSTANCE);
  Jsonix.Schema.XSD.Duration = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
  	name : 'Duration',
  	typeName : Jsonix.Schema.XSD.qname('duration'),
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isObject(value) && (
  				(Jsonix.Util.Type.exists(value.sign) ? (value.sign === -1 || value.sign === 1) : true)
  				(Jsonix.Util.NumberUtils.isInteger(value.years) && value.years >=0) ||
  				(Jsonix.Util.NumberUtils.isInteger(value.months) && value.months >=0) ||
  				(Jsonix.Util.NumberUtils.isInteger(value.days) && value.days >= 0) ||
  				(Jsonix.Util.NumberUtils.isInteger(value.hours) && value.hours >= 0) ||
  				(Jsonix.Util.NumberUtils.isInteger(value.minutes) && value.minutes >= 0) ||
  				(Jsonix.Util.Type.isNumber(value.seconds) && value.seconds >= 0) );
  	},
  	validate : function(value) {
  		Jsonix.Util.Ensure.ensureObject(value);
  		if (Jsonix.Util.Type.exists(value.sign)) {
  			if (!(value.sign === 1 || value.sign === -1)) {
  				throw new Error("Sign of the duration [" + value.sign + "] must be either [1] or [-1].");
  			}
  		}
  		var empty = true;
  		var ifExistsEnsureUnsignedInteger = function(v, message) {
  			if (Jsonix.Util.Type.exists(v)) {
  				if (!(Jsonix.Util.NumberUtils.isInteger(v) && v >= 0)) {
  					throw new Error(message.replace("{0}", v));
  				} else {
  					return true;
  				}
  			} else {
  				return false;
  			}
  		};
  		var ifExistsEnsureUnsignedNumber = function(v, message) {
  			if (Jsonix.Util.Type.exists(v)) {
  				if (!(Jsonix.Util.Type.isNumber(v) && v >= 0)) {
  					throw new Error(message.replace("{0}", v));
  				} else {
  					return true;
  				}
  			} else {
  				return false;
  			}
  		};
  		empty = empty && !ifExistsEnsureUnsignedInteger(value.years, "Number of years [{0}] must be an unsigned integer.");
  		empty = empty && !ifExistsEnsureUnsignedInteger(value.months, "Number of months [{0}] must be an unsigned integer.");
  		empty = empty && !ifExistsEnsureUnsignedInteger(value.days, "Number of days [{0}] must be an unsigned integer.");
  		empty = empty && !ifExistsEnsureUnsignedInteger(value.hours, "Number of hours [{0}] must be an unsigned integer.");
  		empty = empty && !ifExistsEnsureUnsignedInteger(value.minutes, "Number of minutes [{0}] must be an unsigned integer.");
  		empty = empty && !ifExistsEnsureUnsignedNumber(value.seconds, "Number of seconds [{0}] must be an unsigned number.");
  		if (empty) {
  			throw new Error("At least one of the components (years, months, days, hours, minutes, seconds) must be set.");
  		}
  	},
  	print : function(value, context, output, scope) {
  		this.validate(value);
  		var result = '';
  		if (value.sign === -1)
  		{
  			result += '-';
  		}
  		result += 'P';
  		if (Jsonix.Util.Type.exists(value.years)) {
  			result += (value.years + 'Y');
  		}
  		if (Jsonix.Util.Type.exists(value.months)) {
  			result += (value.months + 'M');
  		}
  		if (Jsonix.Util.Type.exists(value.days)) {
  			result += (value.days + 'D');
  		}
  		if (Jsonix.Util.Type.exists(value.hours) || Jsonix.Util.Type.exists(value.minutes) || Jsonix.Util.Type.exists(value.seconds))
  		{
  			result += 'T';
  			if (Jsonix.Util.Type.exists(value.hours)) {
  				result += (value.hours + 'H');
  			}
  			if (Jsonix.Util.Type.exists(value.minutes)) {
  				result += (value.minutes + 'M');
  			}
  			if (Jsonix.Util.Type.exists(value.seconds)) {
  				result += (value.seconds + 'S');
  			}
  		}
  		return result;
  	},
  	parse : function(value, context, input, scope) {
  		var durationExpression = new RegExp("^" + Jsonix.Schema.XSD.Duration.PATTERN + "$");
  		var results = value.match(durationExpression);
  		if (results !== null) {
  			var empty = true;
  			var duration = {};
  			if (results[1]) { duration.sign = -1; }
  			if (results[3]) { duration.years = parseInt(results[3], 10); empty = false; }
  			if (results[5]) { duration.months = parseInt(results[5], 10); empty = false; }
  			if (results[7]) { duration.days = parseInt(results[7], 10); empty = false; }
  			if (results[10]) { duration.hours = parseInt(results[10], 10); empty = false; }
  			if (results[12]) { duration.minutes = parseInt(results[12], 10); empty = false; }
  			if (results[14]) { duration.seconds = Number(results[14]); empty = false; }
  			return duration;
  		} else {
  			throw new Error('Value [' + value + '] does not match the duration pattern.');
  		}
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Duration'
  });
  Jsonix.Schema.XSD.Duration.PATTERN = '(-)?P(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?(T(([0-9]+)H)?(([0-9]+)M)?(([0-9]+(\\.[0-9]+)?)S)?)?';
  Jsonix.Schema.XSD.Duration.INSTANCE = new Jsonix.Schema.XSD.Duration();
  Jsonix.Schema.XSD.Duration.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Duration.INSTANCE);
  Jsonix.Schema.XSD.DateTime = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'DateTime',
  	typeName : Jsonix.Schema.XSD.qname('dateTime'),
  	parse : function(value, context, input, scope) {
  		return this.parseDateTime(value);
  	},
  	print : function(value, context, output, scope) {
  		return this.printDateTime(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.DateTime'
  });
  Jsonix.Schema.XSD.DateTime.INSTANCE = new Jsonix.Schema.XSD.DateTime();
  Jsonix.Schema.XSD.DateTime.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.DateTime.INSTANCE);
  
  Jsonix.Schema.XSD.DateTimeAsDate = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'DateTimeAsDate',
  	typeName : Jsonix.Schema.XSD.qname('dateTime'),
  	parse : function(value, context, input, scope) {
  		var calendar = this.parseDateTime(value);
  		var date = new Date();
  		date.setFullYear(calendar.year);
  		date.setMonth(calendar.month - 1);
  		date.setDate(calendar.day);
  		date.setHours(calendar.hour);
  		date.setMinutes(calendar.minute);
  		date.setSeconds(calendar.second);
  		if (Jsonix.Util.Type.isNumber(calendar.fractionalSecond)) {
  			date.setMilliseconds(Math.floor(1000 * calendar.fractionalSecond));
  		}
  		var timezone;
  		var unknownTimezone;
  		var localTimezone = - date.getTimezoneOffset();
  		if (Jsonix.Util.NumberUtils.isInteger(calendar.timezone))
  		{
  			timezone = calendar.timezone;
  			unknownTimezone = false;
  		}
  		else
  		{
  			// Unknown timezone
  			timezone = localTimezone;
  			unknownTimezone = true;
  		}
  		//
  		var result = new Date(date.getTime() + (60000 * (- timezone + localTimezone)));
  		if (unknownTimezone)
  		{
  			// null denotes "unknown timezone"
  			result.originalTimezone = null;
  		}
  		else
  		{
  			result.originalTimezone = calendar.timezone;
  		}
  		return result;
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureDate(value);
  		var timezone;
  		var localTimezone = - value.getTimezoneOffset();
  		var correctedValue;
  		// If original time zone was unknown, print the given value without
  		// the timezone
  		if (value.originalTimezone === null)
  		{
  			return this.printDateTime(new Jsonix.XML.Calendar({
  				year : value.getFullYear(),
  				month : value.getMonth() + 1,
  				day : value.getDate(),
  				hour : value.getHours(),
  				minute : value.getMinutes(),
  				second : value.getSeconds(),
  				fractionalSecond : (value.getMilliseconds() / 1000)
  			}));
  		}
  		else
  		{
  			// If original timezone was known, correct and print the value with the timezone
  			if (Jsonix.Util.NumberUtils.isInteger(value.originalTimezone))
  			{
  				timezone = value.originalTimezone;
  				correctedValue = new Date(value.getTime() - (60000 * ( - timezone + localTimezone)));
  			}
  			// If original timezone was not specified, do not correct and use the local time zone
  			else
  			{
  				timezone = localTimezone;
  				correctedValue = value;
  			}
  			var x = this.printDateTime(new Jsonix.XML.Calendar({
  				year : correctedValue.getFullYear(),
  				month : correctedValue.getMonth() + 1,
  				day : correctedValue.getDate(),
  				hour : correctedValue.getHours(),
  				minute : correctedValue.getMinutes(),
  				second : correctedValue.getSeconds(),
  				fractionalSecond : (correctedValue.getMilliseconds() / 1000),
  				timezone: timezone
  			}));
  			return x;
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isDate(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.DateTimeAsDate'
  });
  Jsonix.Schema.XSD.DateTimeAsDate.INSTANCE = new Jsonix.Schema.XSD.DateTimeAsDate();
  Jsonix.Schema.XSD.DateTimeAsDate.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.DateTimeAsDate.INSTANCE);
  
  Jsonix.Schema.XSD.Time = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'Time',
  	typeName : Jsonix.Schema.XSD.qname('time'),
  	parse : function(value, context, input, scope) {
  		return this.parseTime(value);
  	},
  	print : function(value, context, output, scope) {
  		return this.printTime(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Time'
  });
  Jsonix.Schema.XSD.Time.INSTANCE = new Jsonix.Schema.XSD.Time();
  Jsonix.Schema.XSD.Time.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Time.INSTANCE);
  Jsonix.Schema.XSD.TimeAsDate = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'TimeAsDate',
  	typeName : Jsonix.Schema.XSD.qname('time'),
  	parse : function(value, context, input, scope) {
  		var calendar = this.parseTime(value);
  		var date = new Date();
  		date.setFullYear(1970);
  		date.setMonth(0);
  		date.setDate(1);
  		date.setHours(calendar.hour);
  		date.setMinutes(calendar.minute);
  		date.setSeconds(calendar.second);
  		if (Jsonix.Util.Type.isNumber(calendar.fractionalSecond)) {
  			date.setMilliseconds(Math.floor(1000 * calendar.fractionalSecond));
  		}
  		var timezone;
  		var unknownTimezone;
  		var localTimezone = - date.getTimezoneOffset();
  		if (Jsonix.Util.NumberUtils.isInteger(calendar.timezone))
  		{
  			timezone = calendar.timezone;
  			unknownTimezone = false;
  		}
  		else
  		{
  			// Unknown timezone
  			timezone = localTimezone;
  			unknownTimezone = true;
  		}
  		//
  		var result = new Date(date.getTime() + (60000 * ( - timezone + localTimezone)));
  		if (unknownTimezone)
  		{
  			// null denotes "unknown timezone"
  			result.originalTimezone = null;
  		}
  		else
  		{
  			result.originalTimezone = timezone;
  		}
  		return result;
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureDate(value);
  		var time = value.getTime();
  		if (time <= -86400000 && time >= 86400000) {
  			throw new Error('Invalid time [' + value + '].');
  		}
  		// Original timezone was unknown, just use current time, no timezone
  		if (value.originalTimezone === null)
  		{
  			return this.printTime(new Jsonix.XML.Calendar({
  				hour : value.getHours(),
  				minute : value.getMinutes(),
  				second : value.getSeconds(),
  				fractionalSecond : (value.getMilliseconds() / 1000)
  			}));
  		}
  		else
  		{
  			var correctedValue;
  			var timezone;
  			var localTimezone = - value.getTimezoneOffset();
  			if (Jsonix.Util.NumberUtils.isInteger(value.originalTimezone))
  			{
  				timezone = value.originalTimezone;
  				correctedValue = new Date(value.getTime() - (60000 * ( - timezone + localTimezone)));
  			}
  			else
  			{
  				timezone = localTimezone;
  				correctedValue = value;
  			}
  			var correctedTime = correctedValue.getTime();
  			if (correctedTime >= (- localTimezone * 60000)) {
  				return this.printTime(new Jsonix.XML.Calendar({
  					hour : correctedValue.getHours(),
  					minute : correctedValue.getMinutes(),
  					second : correctedValue.getSeconds(),
  					fractionalSecond : (correctedValue.getMilliseconds() / 1000),
  					timezone: timezone
  				}));
  			} else {
  				var timezoneHours = Math.ceil(-correctedTime / 3600000);
  				
  				var correctedTimeInSeconds = correctedValue.getSeconds() +
  					correctedValue.getMinutes() * 60 +
  					correctedValue.getHours() * 3600 +
  					timezoneHours * 3600 -
  					timezone * 60;
  				
  				return this.printTime(new Jsonix.XML.Calendar({
  					hour : correctedTimeInSeconds % 86400,
  					minute : correctedTimeInSeconds % 3600,
  					second : correctedTimeInSeconds % 60,
  					fractionalSecond : (correctedValue.getMilliseconds() / 1000),
  					timezone : timezoneHours * 60
  				}));
  			}
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isDate(value) && value.getTime() > -86400000 && value.getTime() < 86400000;
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.TimeAsDate'
  });
  Jsonix.Schema.XSD.TimeAsDate.INSTANCE = new Jsonix.Schema.XSD.TimeAsDate();
  Jsonix.Schema.XSD.TimeAsDate.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.TimeAsDate.INSTANCE);
  Jsonix.Schema.XSD.Date = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'Date',
  	typeName : Jsonix.Schema.XSD.qname('date'),
  	parse : function(value, context, input, scope) {
  		return this.parseDate(value);
  	},
  	print : function(value, context, output, scope) {
  		return this.printDate(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.Date'
  });
  Jsonix.Schema.XSD.Date.INSTANCE = new Jsonix.Schema.XSD.Date();
  Jsonix.Schema.XSD.Date.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.Date.INSTANCE);
  Jsonix.Schema.XSD.DateAsDate = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'DateAsDate',
  	typeName : Jsonix.Schema.XSD.qname('date'),
  	parse : function(value, context, input, scope) {
  		var calendar = this.parseDate(value);
  		var date = new Date();
  		date.setFullYear(calendar.year);
  		date.setMonth(calendar.month - 1);
  		date.setDate(calendar.day);
  		date.setHours(0);
  		date.setMinutes(0);
  		date.setSeconds(0);
  		date.setMilliseconds(0);
  		if (Jsonix.Util.Type.isNumber(calendar.fractionalSecond)) {
  			date.setMilliseconds(Math.floor(1000 * calendar.fractionalSecond));
  		}
  		var timezone;
  		var unknownTimezone;
  		var localTimezone = - date.getTimezoneOffset();
  		if (Jsonix.Util.NumberUtils.isInteger(calendar.timezone))
  		{
  			timezone = calendar.timezone;
  			unknownTimezone = false;
  		}
  		else
  		{
  			// Unknown timezone
  			timezone = localTimezone;
  			unknownTimezone = true;
  		}
  		//
  		var result = new Date(date.getTime() + (60000 * ( - timezone + localTimezone)));
  		if (unknownTimezone)
  		{
  			// null denotes "unknown timezone"
  			result.originalTimezone = null;
  		}
  		else
  		{
  			result.originalTimezone = timezone;
  		}
  		return result;
  	},
  	print : function(value, context, output, scope) {
  		Jsonix.Util.Ensure.ensureDate(value);
  		var localDate = new Date(value.getTime());
  		localDate.setHours(0);
  		localDate.setMinutes(0);
  		localDate.setSeconds(0);
  		localDate.setMilliseconds(0);
  		
  		// Original timezone is unknown
  		if (value.originalTimezone === null)
  		{
  			return this.printDate(new Jsonix.XML.Calendar({
  				year : value.getFullYear(),
  				month : value.getMonth() + 1,
  				day : value.getDate()
  			}));
  		}
  		else
  		{
  			// If original timezone was known, correct and print the value with the timezone
  			if (Jsonix.Util.NumberUtils.isInteger(value.originalTimezone))
  			{
  				var correctedValue = new Date(value.getTime() - (60000 * (- value.originalTimezone - value.getTimezoneOffset())));
  				return this.printDate(new Jsonix.XML.Calendar({
  					year : correctedValue.getFullYear(),
  					month : correctedValue.getMonth() + 1,
  					day : correctedValue.getDate(),
  					timezone : value.originalTimezone
  				}));
  			}
  			// If original timezone was not specified, do not correct and use the local time zone
  			else
  			{
  				// We assume that the difference between the date value and local midnight
  				// should be interpreted as a timezone offset.
  				// In case there's no difference, we assume default/unknown timezone
  				var localTimezone = - value.getTime() + localDate.getTime();
  				if (localTimezone === 0) {
  					return this.printDate(new Jsonix.XML.Calendar({
  						year : value.getFullYear(),
  						month : value.getMonth() + 1,
  						day : value.getDate()
  					}));
  				} else {
  					var timezone = localTimezone - (60000 * value.getTimezoneOffset());
  					if (timezone >= -43200000) {
  						return this.printDate(new Jsonix.XML.Calendar({
  							year : value.getFullYear(),
  							month : value.getMonth() + 1,
  							day : value.getDate(),
  							timezone : Math.floor(timezone / 60000)
  						}));
  					} else {
  						var nextDay = new Date(value.getTime() + 86400000);
  						return this.printDate(new Jsonix.XML.Calendar({
  							year : nextDay.getFullYear(),
  							month : nextDay.getMonth() + 1,
  							day : nextDay.getDate(),
  							timezone : (Math.floor(timezone / 60000) + 1440)
  						}));
  					}
  				}
  			}
  		}
  	},
  	isInstance : function(value, context, scope) {
  		return Jsonix.Util.Type.isDate(value);
  	},
  	CLASS_NAME : 'Jsonix.Schema.XSD.DateAsDate'
  });
  Jsonix.Schema.XSD.DateAsDate.INSTANCE = new Jsonix.Schema.XSD.DateAsDate();
  Jsonix.Schema.XSD.DateAsDate.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.DateAsDate.INSTANCE);
  Jsonix.Schema.XSD.GYearMonth = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'GYearMonth',
  	typeName : Jsonix.Schema.XSD.qname('gYearMonth'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.GYearMonth',
  
  	parse : function(value, context, input, scope) {
  		return this.parseGYearMonth(value, context, input, scope);
  	},
  
  	print : function(value, context, output, scope) {
  		return this.printGYearMonth(value, context, output, scope);
  	}
  
  });
  Jsonix.Schema.XSD.GYearMonth.INSTANCE = new Jsonix.Schema.XSD.GYearMonth();
  Jsonix.Schema.XSD.GYearMonth.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.GYearMonth.INSTANCE);
  Jsonix.Schema.XSD.GYear = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'GYear',
  	typeName : Jsonix.Schema.XSD.qname('gYear'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.GYear',
  
  	parse : function(value, context, input, scope) {
  		return this.parseGYear(value, context, input, scope);
  	},
  
  	print : function(value, context, output, scope) {
  		return this.printGYear(value, context, output, scope);
  	}
  });
  Jsonix.Schema.XSD.GYear.INSTANCE = new Jsonix.Schema.XSD.GYear();
  Jsonix.Schema.XSD.GYear.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.GYear.INSTANCE);
  Jsonix.Schema.XSD.GMonthDay = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'GMonthDay',
  	typeName : Jsonix.Schema.XSD.qname('gMonthDay'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.GMonthDay',
  
  	parse : function(value, context, input, scope) {
  		return this.parseGMonthDay(value, context, input, scope);
  	},
  
  	print : function(value, context, output, scope) {
  		return this.printGMonthDay(value, context, output, scope);
  	}
  });
  Jsonix.Schema.XSD.GMonthDay.INSTANCE = new Jsonix.Schema.XSD.GMonthDay();
  Jsonix.Schema.XSD.GMonthDay.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.GMonthDay.INSTANCE);
  Jsonix.Schema.XSD.GDay = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'GDay',
  	typeName : Jsonix.Schema.XSD.qname('gDay'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.GDay',
  
  	parse : function(value, context, input, scope) {
  		return this.parseGDay(value, context, input, scope);
  	},
  
  	print : function(value, context, output, scope) {
  		return this.printGDay(value, context, output, scope);
  	}
  
  });
  Jsonix.Schema.XSD.GDay.INSTANCE = new Jsonix.Schema.XSD.GDay();
  Jsonix.Schema.XSD.GDay.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.GDay.INSTANCE);
  Jsonix.Schema.XSD.GMonth = Jsonix.Class(Jsonix.Schema.XSD.Calendar, {
  	name : 'GMonth',
  	typeName : Jsonix.Schema.XSD.qname('gMonth'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.GMonth',
  	parse : function(value, context, input, scope) {
  		return this.parseGMonth(value, context, input, scope);
  	},
  	print : function(value, context, output, scope) {
  		return this.printGMonth(value, context, output, scope);
  	}
  });
  Jsonix.Schema.XSD.GMonth.INSTANCE = new Jsonix.Schema.XSD.GMonth();
  Jsonix.Schema.XSD.GMonth.INSTANCE.LIST = new Jsonix.Schema.XSD.List(Jsonix.Schema.XSD.GMonth.INSTANCE);
  Jsonix.Schema.XSD.ID = Jsonix.Class(Jsonix.Schema.XSD.String, {
  	name : 'ID',
  	typeName : Jsonix.Schema.XSD.qname('ID'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.ID'
  });
  Jsonix.Schema.XSD.ID.INSTANCE = new Jsonix.Schema.XSD.ID();
  Jsonix.Schema.XSD.ID.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.ID.INSTANCE);
  Jsonix.Schema.XSD.IDREF = Jsonix.Class(Jsonix.Schema.XSD.String, {
  	name : 'IDREF',
  	typeName : Jsonix.Schema.XSD.qname('IDREF'),
  	CLASS_NAME : 'Jsonix.Schema.XSD.IDREF'
  });
  Jsonix.Schema.XSD.IDREF.INSTANCE = new Jsonix.Schema.XSD.IDREF();
  Jsonix.Schema.XSD.IDREF.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
  		Jsonix.Schema.XSD.IDREF.INSTANCE);
  Jsonix.Schema.XSD.IDREFS = Jsonix.Class(Jsonix.Schema.XSD.List, {
  	name : 'IDREFS',
  	initialize : function() {
  		Jsonix.Schema.XSD.List.prototype.initialize.apply(this, [ Jsonix.Schema.XSD.IDREF.INSTANCE, Jsonix.Schema.XSD.qname('IDREFS'), ' ' ]);
  	},
  	// TODO Constraints
  	CLASS_NAME : 'Jsonix.Schema.XSD.IDREFS'
  });
  Jsonix.Schema.XSD.IDREFS.INSTANCE = new Jsonix.Schema.XSD.IDREFS();
  Jsonix.Schema.XSI = {};
  Jsonix.Schema.XSI.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema-instance';
  Jsonix.Schema.XSI.PREFIX = 'xsi';
  Jsonix.Schema.XSI.TYPE = 'type';
  Jsonix.Schema.XSI.NIL = 'nil';
  Jsonix.Schema.XSI.qname = function(localPart) {
  	Jsonix.Util.Ensure.ensureString(localPart);
  	return new Jsonix.XML.QName(Jsonix.Schema.XSI.NAMESPACE_URI, localPart,
  			Jsonix.Schema.XSI.PREFIX);
  };
  Jsonix.Schema.XSI.TYPE_QNAME = Jsonix.Schema.XSI.qname(Jsonix.Schema.XSI.TYPE);
  
  Jsonix.Context = Jsonix
  		.Class(Jsonix.Mapping.Styled, {
  			modules : [],
  			typeInfos : null,
  			typeNameKeyToTypeInfo : null,
  			elementInfos : null,
  			options : null,
  			substitutionMembersMap : null,
  			scopedElementInfosMap : null,
  			supportXsiType : true,
  			initialize : function(mappings, options) {
  				Jsonix.Mapping.Styled.prototype.initialize.apply(this, [options]);
  				this.modules = [];
  				this.elementInfos = [];
  				this.typeInfos = {};
  				this.typeNameKeyToTypeInfo = {};
  				this.registerBuiltinTypeInfos();
  				this.namespacePrefixes = {};
  				this.prefixNamespaces = {};
  				this.substitutionMembersMap = {};
  				this.scopedElementInfosMap = {};
  
  				// Initialize options
  				if (Jsonix.Util.Type.exists(options)) {
  					Jsonix.Util.Ensure.ensureObject(options);
  					if (Jsonix.Util.Type
  							.isObject(options.namespacePrefixes)) {
  						this.namespacePrefixes =
  							Jsonix.Util.Type.cloneObject(options.namespacePrefixes, {});
  					}
  					if (Jsonix.Util.Type
  							.isBoolean(options.supportXsiType)) {
  						this.supportXsiType = options.supportXsiType;
  					}
  				}
  
  				// Initialize prefix/namespace mapping
  				for (var ns in this.namespacePrefixes)
  				{
  					if (this.namespacePrefixes.hasOwnProperty(ns))
  					{
  						p = this.namespacePrefixes[ns];
  						this.prefixNamespaces[p] = ns;
  					}
  				}
  				// Initialize modules
  				if (Jsonix.Util.Type.exists(mappings)) {
  					Jsonix.Util.Ensure.ensureArray(mappings);
  					// Initialize modules
  					var index, mapping, module;
  					for (index = 0; index < mappings.length; index++) {
  						mapping = mappings[index];
  						module = this.createModule(mapping);
  						this.modules[index] = module;
  					}
  				}
  				this.processModules();
  			},
  			createModule : function(mapping) {
  				var module;
  				if (mapping instanceof this.mappingStyle.module) {
  					module = mapping;
  				} else {
  					mapping = Jsonix.Util.Type.cloneObject(mapping);
  					module = new this.mappingStyle.module(mapping,
  					{
  						mappingStyle : this.mappingStyle
  					});
  				}
  				return module;
  			},
  			registerBuiltinTypeInfos : function() {
  				for ( var index = 0; index < this.builtinTypeInfos.length; index++) {
  					this.registerTypeInfo(this.builtinTypeInfos[index]);
  				}
  			},
  			processModules : function() {
  				var index, module;
  				for (index = 0; index < this.modules.length; index++) {
  					module = this.modules[index];
  					module.registerTypeInfos(this);
  				}
  				for (index = 0; index < this.modules.length; index++) {
  					module = this.modules[index];
  					module.registerElementInfos(this);
  				}
  				for (index = 0; index < this.modules.length; index++) {
  					module = this.modules[index];
  					module.buildTypeInfos(this);
  				}
  				for (index = 0; index < this.modules.length; index++) {
  					module = this.modules[index];
  					module.buildElementInfos(this);
  				}
  			},
  			registerTypeInfo : function(typeInfo) {
  				Jsonix.Util.Ensure.ensureObject(typeInfo);
  				var n = typeInfo.name||typeInfo.n||null;
  				Jsonix.Util.Ensure.ensureString(n);
  				this.typeInfos[n] = typeInfo;
  				if (typeInfo.typeName && typeInfo.typeName.key)
  				{
  					this.typeNameKeyToTypeInfo[typeInfo.typeName.key] = typeInfo;
  				}
  			},
  			resolveTypeInfo : function(mapping, module) {
  				if (!Jsonix.Util.Type.exists(mapping)) {
  					return null;
  				} else if (mapping instanceof Jsonix.Model.TypeInfo) {
  					return mapping;
  				} else if (Jsonix.Util.Type.isString(mapping)) {
  					var typeInfoName;
  					// If mapping starts with '.' consider it to be a local type name in this module
  					if (mapping.length > 0 && mapping.charAt(0) === '.')
  					{
  						var n = module.name || module.n || undefined;
  						Jsonix.Util.Ensure.ensureObject(module, 'Type info mapping can only be resolved if module is provided.');
  						Jsonix.Util.Ensure.ensureString(n, 'Type info mapping can only be resolved if module name is provided.');
  						typeInfoName = n + mapping;
  					}
  					else
  					{
  						typeInfoName = mapping;
  					}
  					if (!this.typeInfos[typeInfoName]) {
  						throw new Error('Type info [' + typeInfoName + '] is not known in this context.');
  					} else {
  						return this.typeInfos[typeInfoName];
  					}
  				} else {
  					Jsonix.Util.Ensure.ensureObject(module, 'Type info mapping can only be resolved if module is provided.');
  					var typeInfo = module.createTypeInfo(mapping);
  					typeInfo.build(this, module);
  					return typeInfo;
  				}
  			},
  			registerElementInfo : function(elementInfo, module) {
  				Jsonix.Util.Ensure.ensureObject(elementInfo);
  				this.elementInfos.push(elementInfo);
  
  				if (Jsonix.Util.Type.exists(elementInfo.substitutionHead)) {
  					var substitutionHead = elementInfo.substitutionHead;
  					var substitutionHeadKey = substitutionHead.key;
  					var substitutionMembers = this.substitutionMembersMap[substitutionHeadKey];
  
  					if (!Jsonix.Util.Type.isArray(substitutionMembers)) {
  						substitutionMembers = [];
  						this.substitutionMembersMap[substitutionHeadKey] = substitutionMembers;
  					}
  					substitutionMembers.push(elementInfo);
  				}
  
  				var scopeKey;
  				if (Jsonix.Util.Type.exists(elementInfo.scope)) {
  					scopeKey = this.resolveTypeInfo(elementInfo.scope, module).name;
  				} else {
  					scopeKey = '##global';
  				}
  
  				var scopedElementInfos = this.scopedElementInfosMap[scopeKey];
  
  				if (!Jsonix.Util.Type.isObject(scopedElementInfos)) {
  					scopedElementInfos = {};
  					this.scopedElementInfosMap[scopeKey] = scopedElementInfos;
  				}
  				scopedElementInfos[elementInfo.elementName.key] = elementInfo;
  
  			},
  			getTypeInfoByValue : function(value)
  			{
  				if (!Jsonix.Util.Type.exists(value))
  				{
  					return undefined;
  				}
  				if (Jsonix.Util.Type.isObject(value))
  				{
  					var typeName = value.TYPE_NAME;
  					if (Jsonix.Util.Type.isString(typeName))
  					{
  						var typeInfoByName = this.getTypeInfoByName(typeName);
  						if (typeInfoByName)
  						{
  							return typeInfoByName;
  						}
  					}
  				}
  				return undefined;
  			},
  			// TODO public API
  			getTypeInfoByName : function(name) {
  				return this.typeInfos[name];
  			},
  			getTypeInfoByTypeName : function(typeName) {
  				var tn = Jsonix.XML.QName.fromObjectOrString(typeName, this);
  				return this.typeNameKeyToTypeInfo[tn.key];
  			},
  			getTypeInfoByTypeNameKey : function(typeNameKey) {
  				return this.typeNameKeyToTypeInfo[typeNameKey];
  			},
  			getElementInfo : function(name, scope) {
  				if (Jsonix.Util.Type.exists(scope)) {
  					var scopeKey = scope.name;
  					var scopedElementInfos = this.scopedElementInfosMap[scopeKey];
  					if (Jsonix.Util.Type.exists(scopedElementInfos)) {
  						var scopedElementInfo = scopedElementInfos[name.key];
  						if (Jsonix.Util.Type.exists(scopedElementInfo)) {
  							return scopedElementInfo;
  						}
  					}
  				}
  
  				var globalScopeKey = '##global';
  				var globalScopedElementInfos = this.scopedElementInfosMap[globalScopeKey];
  				if (Jsonix.Util.Type.exists(globalScopedElementInfos)) {
  					var globalScopedElementInfo = globalScopedElementInfos[name.key];
  					if (Jsonix.Util.Type.exists(globalScopedElementInfo)) {
  						return globalScopedElementInfo;
  					}
  				}
  				return null;
  				//
  				// throw new Error("Element [" + name.key
  				// + "] could not be found in the given context.");
  			},
  			getSubstitutionMembers : function(name) {
  				return this.substitutionMembersMap[Jsonix.XML.QName
  						.fromObject(name).key];
  			},
  			createMarshaller : function() {
  				return new this.mappingStyle.marshaller(this);
  			},
  			createUnmarshaller : function() {
  				return new this.mappingStyle.unmarshaller(this);
  			},
  			getNamespaceURI : function(prefix) {
  				Jsonix.Util.Ensure.ensureString(prefix);
  				return this.prefixNamespaces[prefix];
  			},
  			getPrefix : function(namespaceURI, defaultPrefix) {
  				Jsonix.Util.Ensure.ensureString(namespaceURI);
  				var prefix = this.namespacePrefixes[namespaceURI];
  				if (Jsonix.Util.Type.isString(prefix))
  				{
  					return prefix;
  				}
  				else
  				{
  					return defaultPrefix;
  				}
  			},
  			/**
  			 * Builtin type infos.
  			 */
  			builtinTypeInfos : [
  			        Jsonix.Schema.XSD.AnyType.INSTANCE,
  			        Jsonix.Schema.XSD.AnySimpleType.INSTANCE,
  					Jsonix.Schema.XSD.AnyURI.INSTANCE,
  					Jsonix.Schema.XSD.Base64Binary.INSTANCE,
  					Jsonix.Schema.XSD.Boolean.INSTANCE,
  					Jsonix.Schema.XSD.Byte.INSTANCE,
  					Jsonix.Schema.XSD.Calendar.INSTANCE,
  					Jsonix.Schema.XSD.DateAsDate.INSTANCE,
  					Jsonix.Schema.XSD.Date.INSTANCE,
  					Jsonix.Schema.XSD.DateTimeAsDate.INSTANCE,
  					Jsonix.Schema.XSD.DateTime.INSTANCE,
  					Jsonix.Schema.XSD.Decimal.INSTANCE,
  					Jsonix.Schema.XSD.Double.INSTANCE,
  					Jsonix.Schema.XSD.Duration.INSTANCE,
  					Jsonix.Schema.XSD.Float.INSTANCE,
  					Jsonix.Schema.XSD.GDay.INSTANCE,
  					Jsonix.Schema.XSD.GMonth.INSTANCE,
  					Jsonix.Schema.XSD.GMonthDay.INSTANCE,
  					Jsonix.Schema.XSD.GYear.INSTANCE,
  					Jsonix.Schema.XSD.GYearMonth.INSTANCE,
  					Jsonix.Schema.XSD.HexBinary.INSTANCE,
  					Jsonix.Schema.XSD.ID.INSTANCE,
  					Jsonix.Schema.XSD.IDREF.INSTANCE,
  					Jsonix.Schema.XSD.IDREFS.INSTANCE,
  					Jsonix.Schema.XSD.Int.INSTANCE,
  					Jsonix.Schema.XSD.Integer.INSTANCE,
  					Jsonix.Schema.XSD.Language.INSTANCE,
  					Jsonix.Schema.XSD.Long.INSTANCE,
  					Jsonix.Schema.XSD.Name.INSTANCE,
  					Jsonix.Schema.XSD.NCName.INSTANCE,
  					Jsonix.Schema.XSD.NegativeInteger.INSTANCE,
  					Jsonix.Schema.XSD.NMToken.INSTANCE,
  					Jsonix.Schema.XSD.NMTokens.INSTANCE,
  					Jsonix.Schema.XSD.NonNegativeInteger.INSTANCE,
  					Jsonix.Schema.XSD.NonPositiveInteger.INSTANCE,
  					Jsonix.Schema.XSD.NormalizedString.INSTANCE,
  					Jsonix.Schema.XSD.Number.INSTANCE,
  					Jsonix.Schema.XSD.PositiveInteger.INSTANCE,
  					Jsonix.Schema.XSD.QName.INSTANCE,
  					Jsonix.Schema.XSD.Short.INSTANCE,
  					Jsonix.Schema.XSD.String.INSTANCE,
  					Jsonix.Schema.XSD.Strings.INSTANCE,
  					Jsonix.Schema.XSD.TimeAsDate.INSTANCE,
  					Jsonix.Schema.XSD.Time.INSTANCE,
  					Jsonix.Schema.XSD.Token.INSTANCE,
  					Jsonix.Schema.XSD.UnsignedByte.INSTANCE,
  					Jsonix.Schema.XSD.UnsignedInt.INSTANCE,
  					Jsonix.Schema.XSD.UnsignedLong.INSTANCE,
  					Jsonix.Schema.XSD.UnsignedShort.INSTANCE ],
  			CLASS_NAME : 'Jsonix.Context'
  		});
  
  	// Complete Jsonix script is included above
  	return { Jsonix: Jsonix };
  };
  
  // If the require function exists ...
  if (typeof require === 'function') {
  	// ... but the define function does not exists
  	if (typeof define !== 'function') {
  		// Load the define function via amdefine
  		var define = require('amdefine')(module);
  		// If we're not in browser
  		if (typeof window === 'undefined')
  		{
  			// Require xmldom, xmlhttprequest and fs
  			define(["xmldom", "xmlhttprequest", "fs"], _jsonix_factory);
  		}
  		else
  		{
  			// We're probably in browser, maybe browserify
  			// Do not require xmldom, xmlhttprequest as they'r provided by the browser
  			// Do not require fs since file system is not available anyway
  			define([], _jsonix_factory);
  		}
  	}
  	else {
  		// Otherwise assume we're in the browser/RequireJS environment
  		// Load the module without xmldom and xmlhttprequests dependencies
  		define([], _jsonix_factory);
  	}
  }
  // If the require function does not exists, we're not in Node.js and therefore in browser environment
  else
  {
  	// Just call the factory and set Jsonix as global.
  	var Jsonix = _jsonix_factory().Jsonix;
  }
  