PageSourceSearch

https://www.eighteenthcenturypoetry.org/js/jsonform-2.1.4/deps/opt/jsv.js

js eighteenthcenturypoetry.org collected 2026-09-24 21:27:07 UTC 115,748 bytes, 3,700 lines download raw bytes

1// This is a build of https://github.com/garycourt/JSV at 0aa11852537069b0830569ef1eab11a36b65b3ab with jsv.js, schema03 and URI.js appended.
2// The build contains a few lines of custom code to handle format validation.
3// Custom code is wrapped in comments that start with "JOSHFIRE"
4(function(global, require) {
5var exports = {};
6
7
8
9/**
10 * URI.js
11 * 
12 * @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript.
13 * @author <a href="mailto:[email protected]">Gary Court</a>
14 * @version 1.2
15 * @see http://github.com/garycourt/uri-js
16 * @license URI.js v1.2 (c) 2010 Gary Court. License: http://github.com/garycourt/uri-js
17 */
18
19/**
20 * Copyright 2010 Gary Court. All rights reserved.
21 * 
22 * Redistribution and use in source and binary forms, with or without modification, are
23 * permitted provided that the following conditions are met:
24 * 
25 *    1. Redistributions of source code must retain the above copyright notice, this list of
26 *       conditions and the following disclaimer.
27 * 
28 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
29 *       of conditions and the following disclaimer in the documentation and/or other materials
30 *       provided with the distribution.
31 * 
32 * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
38 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
39 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
40 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * 
42 * The views and conclusions contained in the software and documentation are those of the
43 * authors and should not be interpreted as representing official policies, either expressed
44 * or implied, of Gary Court.
45 */
46
47/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
48/*global exports:true, require:true */
49
50if (typeof exports === "undefined") {
51	exports = {}; 
52}
53if (typeof require !== "function") {
54	require = function (id) {
55		return exports;
56	};
57}
58(function () {
59	var	
60		/**
61		 * @param {...string} sets
62		 * @return {string}
63		 */
64		mergeSet = function (sets) {
65			var set = arguments[0],
66				x = 1,
67				nextSet = arguments[x];
68
69			while (nextSet) {
70				set = set.slice(0, -1) + nextSet.slice(1);
71				nextSet = arguments[++x];
72			}
73
74			return set;
75		},
76
77		/**
78		 * @param {string} str
79		 * @return {string}
80		 */
81		subexp = function (str) {
82			return "(?:" + str + ")";
83		},
84
85		ALPHA$$ = "[A-Za-z]",
86		CR$ = "[\\x0D]",
87		DIGIT$$ = "[0-9]",
88		DQUOTE$$ = "[\\x22]",
89		HEXDIG$$ = mergeSet(DIGIT$$, "[A-Fa-f]"),  //case-insensitive
90		LF$$ = "[\\x0A]",
91		SP$$ = "[\\x20]",
92		PCT_ENCODED$ = subexp("%" + HEXDIG$$ + HEXDIG$$),
93		GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]",
94		SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]",
95		RESERVED$$ = mergeSet(GEN_DELIMS$$, SUB_DELIMS$$),
96		UNRESERVED$$ = mergeSet(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]"),
97		SCHEME$ = subexp(ALPHA$$ + mergeSet(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"),
98		USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"),
99		DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$),
100		IPV4ADDRESS$ = subexp(DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$),
101		H16$ = subexp(HEXDIG$$ + "{1,4}"),
102		LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$),
103		IPV6ADDRESS$ = subexp(mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),  //FIXME
104		IPVFUTURE$ = subexp("v" + HEXDIG$$ + "+\\." + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),
105		IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"),
106		REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$)) + "*"),
107		HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "|" + REG_NAME$),
108		PORT$ = subexp(DIGIT$$ + "*"),
109		AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"),
110		PCHAR$ = subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")),
111		SEGMENT$ = subexp(PCHAR$ + "*"),
112		SEGMENT_NZ$ = subexp(PCHAR$ + "+"),
113		SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"),
114		PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"),
115		PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"),  //simplified
116		PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$),  //simplified
117		PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$),  //simplified
118		PATH_EMPTY$ = subexp(""),  //simplified
119		PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
120		QUERY$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
121		FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
122		HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
123		URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
124		RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$),
125		RELATIVE_REF$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
126		URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE_REF$),
127		ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"),
128
129		URI_REF = new RegExp("^" + subexp("(" + URI$ + ")|(" + RELATIVE_REF$ + ")") + "$"),
130		GENERIC_REF  = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
131		RELATIVE_REF = new RegExp("^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
132		ABSOLUTE_REF = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$"),
133		SAMEDOC_REF = new RegExp("^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
134		AUTHORITY = new RegExp("^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$"),
135
136		NOT_SCHEME = new RegExp(mergeSet("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"),
137		NOT_USERINFO = new RegExp(mergeSet("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
138		NOT_HOST = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$), "g"),
139		NOT_PATH = new RegExp(mergeSet("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
140		NOT_PATH_NOSCHEME = new RegExp(mergeSet("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
141		NOT_QUERY = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"),
142		NOT_FRAGMENT = NOT_QUERY,
143		ESCAPE = new RegExp(mergeSet("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"),
144		UNRESERVED = new RegExp(UNRESERVED$$, "g"),
145		OTHER_CHARS = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, RESERVED$$), "g"),
146		PCT_ENCODEDS = new RegExp(PCT_ENCODED$ + "+", "g"),
147		URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/i,
148		RDS1 = /^\.\.?\//,
149		RDS2 = /^\/\.(\/|$)/,
150		RDS3 = /^\/\.\.(\/|$)/,
151		RDS4 = /^\.\.?$/,
152		RDS5 = /^\/?.*?(?=\/|$)/,
153		NO_MATCH_IS_UNDEFINED = ("").match(/(){0}
153/)[1] === undefined,
154
155		/**
156		 * @param {string} chr
157		 * @return {string}
158		 */
159		pctEncChar = function (chr) {
160			var c = chr.charCodeAt(0);
161 
162			if (c < 128) {
163				return "%" + c.toString(16).toUpperCase();
164			}
165			else if ((c > 127) && (c < 2048)) {
166				return "%" + ((c >> 6) | 192).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
167			}
168			else {
169				return "%" + ((c >> 12) | 224).toString(16).toUpperCase() + "%" + (((c >> 6) & 63) | 128).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
170			}
171		},
172
173		/**
174		 * @param {string} str
175		 * @return {string}
176		 */
177		pctDecUnreserved = function (str) {
178			var newStr = "", 
179				i = 0,
180				c, s;
181
182			while (i < str.length) {
183				c = parseInt(str.substr(i + 1, 2), 16);
184
185				if (c < 128) {
186					s = String.fromCharCode(c);
187					if (s.match(UNRESERVED)) {
188						newStr += s;
189					} else {
190						newStr += str.substr(i, 3);
191					}
192					i += 3;
193				}
194				else if ((c > 191) && (c < 224)) {
195					newStr += str.substr(i, 6);
196					i += 6;
197				}
198				else {
199					newStr += str.substr(i, 9);
200					i += 9;
201				}
202			}
203
204			return newStr;
205		},
206
207		/**
208		 * @param {string} str
209		 * @return {string}
210		 */
211		pctDecChars = function (str) {
212			var newStr = "", 
213				i = 0,
214				c, c2, c3;
215
216			while (i < str.length) {
217				c = parseInt(str.substr(i + 1, 2), 16);
218
219				if (c < 128) {
220					newStr += String.fromCharCode(c);
221					i += 3;
222				}
223				else if ((c > 191) && (c < 224)) {
224					c2 = parseInt(str.substr(i + 4, 2), 16);
225					newStr += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
226					i += 6;
227				}
228				else {
229					c2 = parseInt(str.substr(i + 4, 2), 16);
230					c3 = parseInt(str.substr(i + 7, 2), 16);
231					newStr += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
232					i += 9;
233				}
234			}
235
236			return newStr;
237		},
238
239		/**
240		 * @return {string}
241		 */
242		typeOf = function (o) {
243			return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
244		},
245
246		/**
247		 * @constructor
248		 * @implements URIComponents
249		 */
250		Components = function () {
251			this.errors = [];
252		}, 
253
254		/** @namespace */ 
255		URI = {};
256
257	/**
258	 * Components
259	 */
260
261	Components.prototype = {
262		/**
263		 * @type String
264		 */
265
266		scheme : undefined,
267
268		/**
269		 * @type String
270		 */
271
272		authority : undefined,
273
274		/**
275		 * @type String
276		 */
277
278		userinfo : undefined,
279
280		/**
281		 * @type String
282		 */
283
284		host : undefined,
285
286		/**
287		 * @type number
288		 */
289
290		port : undefined,
291
292		/**
293		 * @type string
294		 */
295
296		path : undefined,
297
298		/**
299		 * @type string
300		 */
301
302		query : undefined,
303
304		/**
305		 * @type string
306		 */
307
308		fragment : undefined,
309
310		/**
311		 * @type string
312		 * @values "uri", "absolute", "relative", "same-document"
313		 */
314
315		reference : undefined,
316
317		/**
318		 * @type Array
319		 */
320
321		errors : undefined
322	};
323
324	/**
325	 * URI
326	 */
327
328	/**
329	 * @namespace
330	 */
331
332	URI.SCHEMES = {};
333
334	/**
335	 * @param {string} uriString
336	 * @param {Options} [options]
337	 * @returns {URIComponents}
338	 */
339
340	URI.parse = function (uriString, options) {
341		var matches, 
342			components = new Components(),
343			schemeHandler;
344
345		uriString = uriString ? uriString.toString() : "";
346		options = options || {};
347
348		if (options.reference === "suffix") {
349			uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString;
350		}
351
352		matches = uriString.match(URI_REF);
353
354		if (matches) {
355			if (matches[1]) {
356				//generic URI
357				matches = uriString.match(GENERIC_REF);
358			} else {
359				//relative URI
360				matches = uriString.match(RELATIVE_REF);
361			}
362		} 
363
364		if (!matches) {
365			if (!options.tolerant) {
366				components.errors.push("URI is not strictly valid.");
367			}
368			matches = uriString.match(URI_PARSE);
369		}
370
371		if (matches) {
372			if (NO_MATCH_IS_UNDEFINED) {
373				//store each component
374				components.scheme = matches[1];
375				components.authority = matches[2];
376				components.userinfo = matches[3];
377				components.host = matches[4];
378				components.port = parseInt(matches[5], 10);
379				components.path = matches[6] || "";
380				components.query = matches[7];
381				components.fragment = matches[8];
382
383				//fix port number
384				if (isNaN(components.port)) {
385					components.port = matches[5];
386				}
387			} else {  //IE FIX for improper RegExp matching
388				//store each component
389				components.scheme = matches[1] || undefined;
390				components.authority = (uriString.indexOf("//") !== -1 ? matches[2] : undefined);
391				components.userinfo = (uriString.indexOf("@") !== -1 ? matches[3] : undefined);
392				components.host = (uriString.indexOf("//") !== -1 ? matches[4] : undefined);
393				components.port = parseInt(matches[5], 10);
394				components.path = matches[6] || "";
395				components.query = (uriString.indexOf("?") !== -1 ? matches[7] : undefined);
396				components.fragment = (uriString.indexOf("#") !== -1 ? matches[8] : undefined);
397
398				//fix port number
399				if (isNaN(components.port)) {
400					components.port = (uriString.match(/\/\/.*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined);
401				}
402			}
403
404			//determine reference type
405			if (!components.scheme && !components.authority && !components.path && !components.query) {
406				components.reference = "same-document";
407			} else if (!components.scheme) {
408				components.reference = "relative";
409			} else if (!components.fragment) {
410				components.reference = "absolute";
411			} else {
412				components.reference = "uri";
413			}
414
415			//check for reference errors
416			if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) {
417				components.errors.push("URI is not a " + options.reference + " reference.");
418			}
419
420			//check if a handler for the scheme exists
421			schemeHandler = URI.SCHEMES[components.scheme || options.scheme];
422			if (schemeHandler && schemeHandler.parse) {
423				//perform extra parsing
424				schemeHandler.parse(components, options);
425			}
426		} else {
427			components.errors.push("URI can not be parsed.");
428		}
429
430		return components;
431	};
432
433	/**
434	 * @private
435	 * @param {URIComponents} components
436	 * @returns {string|undefined}
437	 */
438
439	URI._recomposeAuthority = function (components) {
440		var uriTokens = [];
441
442		if (components.userinfo !== undefined || components.host !== undefined || typeof components.port === "number") {
443			if (components.userinfo !== undefined) {
444				uriTokens.push(components.userinfo.toString().replace(NOT_USERINFO, pctEncChar));
445				uriTokens.push("@");
446			}
447			if (components.host !== undefined) {
448				uriTokens.push(components.host.toString().toLowerCase().replace(NOT_HOST, pctEncChar));
449			}
450			if (typeof components.port === "number") {
451				uriTokens.push(":");
452				uriTokens.push(components.port.toString(10));
453			}
454		}
455
456		return uriTokens.length ? uriTokens.join("") : undefined;
457	};
458
459	/**
460	 * @param {string} input
461	 * @returns {string}
462	 */
463
464	URI.removeDotSegments = function (input) {
465		var output = [], s;
466
467		while (input.length) {
468			if (input.match(RDS1)) {
469				input = input.replace(RDS1, "");
470			} else if (input.match(RDS2)) {
471				input = input.replace(RDS2, "/");
472			} else if (input.match(RDS3)) {
473				input = input.replace(RDS3, "/");
474				output.pop();
475			} else if (input === "." || input === "..") {
476				input = "";
477			} else {
478				s = input.match(RDS5)[0];
479				input = input.slice(s.length);
480				output.push(s);
481			}
482		}
483
484		return output.join("");
485	};
486
487	/**
488	 * @param {URIComponents} components
489	 * @param {Options} [options]
490	 * @returns {string}
491	 */
492
493	URI.serialize = function (components, options) {
494		var uriTokens = [], 
495			schemeHandler, 
496			s;
497		options = options || {};
498
499		//check if a handler for the scheme exists
500		schemeHandler = URI.SCHEMES[components.scheme || options.scheme];
501		if (schemeHandler && schemeHandler.serialize) {
502			//perform extra serialization
503			schemeHandler.serialize(components, options);
504		}
505
506		if (options.reference !== "suffix" && components.scheme) {
507			uriTokens.push(components.scheme.toString().toLowerCase().replace(NOT_SCHEME, ""));
508			uriTokens.push(":");
509		}
510
511		components.authority = URI._recomposeAuthority(components);
512		if (components.authority !== undefined) {
513			if (options.reference !== "suffix") {
514				uriTokens.push("//");
515			}
516
517			uriTokens.push(components.authority);
518
519			if (components.path && components.path.charAt(0) !== "/") {
520				uriTokens.push("/");
521			}
522		}
523
524		if (components.path) {
525			s = URI.removeDotSegments(components.path.toString().replace(/%2E/ig, "."));
526
527			if (components.scheme) {
528				s = s.replace(NOT_PATH, pctEncChar);
529			} else {
530				s = s.replace(NOT_PATH_NOSCHEME, pctEncChar);
531			}
532
533			if (components.authority === undefined) {
534				s = s.replace(/^\/\//, "/%2F");  //don't allow the path to start with "//"
535			}
536			uriTokens.push(s);
537		}
538
539		if (components.query) {
540			uriTokens.push("?");
541			uriTokens.push(components.query.toString().replace(NOT_QUERY, pctEncChar));
542		}
543
544		if (components.fragment) {
545			uriTokens.push("#");
546			uriTokens.push(components.fragment.toString().replace(NOT_FRAGMENT, pctEncChar));
547		}
548
549		return uriTokens
550			.join('')  //merge tokens into a string
551			.replace(PCT_ENCODEDS, pctDecUnreserved)  //undecode unreserved characters
552			//.replace(OTHER_CHARS, pctEncChar)  //replace non-URI characters
553			.replace(/%[0-9A-Fa-f]{2}/g, function (str) {  //uppercase percent encoded characters
554				return str.toUpperCase();
555			})
556		;
557	};
558
559	/**
560	 * @param {URIComponents} base
561	 * @param {URIComponents} relative
562	 * @param {Options} [options]
563	 * @param {boolean} [skipNormalization]
564	 * @returns {URIComponents}
565	 */
566
567	URI.resolveComponents = function (base, relative, options, skipNormalization) {
568		var target = new Components();
569
570		if (!skipNormalization) {
571			base = URI.parse(URI.serialize(base, options), options);  //normalize base components
572			relative = URI.parse(URI.serialize(relative, options), options);  //normalize relative components
573		}
574		options = options || {};
575
576		if (!options.tolerant && relative.scheme) {
577			target.scheme = relative.scheme;
578			target.authority = relative.authority;
579			target.userinfo = relative.userinfo;
580			target.host = relative.host;
581			target.port = relative.port;
582			target.path = URI.removeDotSegments(relative.path);
583			target.query = relative.query;
584		} else {
585			if (relative.authority !== undefined) {
586				target.authority = relative.authority;
587				target.userinfo = relative.userinfo;
588				target.host = relative.host;
589				target.port = relative.port;
590				target.path = URI.removeDotSegments(relative.path);
591				target.query = relative.query;
592			} else {
593				if (!relative.path) {
594					target.path = base.path;
595					if (relative.query !== undefined) {
596						target.query = relative.query;
597					} else {
598						target.query = base.query;
599					}
600				} else {
601					if (relative.path.charAt(0) === "/") {
602						target.path = URI.removeDotSegments(relative.path);
603					} else {
604						if (base.authority !== undefined && !base.path) {
605							target.path = "/" + relative.path;
606						} else if (!base.path) {
607							target.path = relative.path;
608						} else {
609							target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
610						}
611						target.path = URI.removeDotSegments(target.path);
612					}
613					target.query = relative.query;
614				}
615				target.authority = base.authority;
616				target.userinfo = base.userinfo;
617				target.host = base.host;
618				target.port = base.port;
619			}
620			target.scheme = base.scheme;
621		}
622
623		target.fragment = relative.fragment;
624
625		return target;
626	};
627
628	/**
629	 * @param {string} baseURI
630	 * @param {string} relativeURI
631	 * @param {Options} [options]
632	 * @returns {string}
633	 */
634
635	URI.resolve = function (baseURI, relativeURI, options) {
636		return URI.serialize(URI.resolveComponents(URI.parse(baseURI, options), URI.parse(relativeURI, options), options, true), options);
637	};
638
639	/**
640	 * @param {string|URIComponents} uri
641	 * @param {Options} options
642	 * @returns {string|URIComponents}
643	 */
644
645	URI.normalize = function (uri, options) {
646		if (typeof uri === "string") {
647			return URI.serialize(URI.parse(uri, options), options);
648		} else if (typeOf(uri) === "object") {
649			return URI.parse(URI.serialize(uri, options), options);
650		}
651
652		return uri;
653	};
654
655	/**
656	 * @param {string|URIComponents} uriA
657	 * @param {string|URIComponents} uriB
658	 * @param {Options} options
659	 */
660
661	URI.equal = function (uriA, uriB, options) {
662		if (typeof uriA === "string") {
663			uriA = URI.serialize(URI.parse(uriA, options), options);
664		} else if (typeOf(uriA) === "object") {
665			uriA = URI.serialize(uriA, options);
666		}
667
668		if (typeof uriB === "string") {
669			uriB = URI.serialize(URI.parse(uriB, options), options);
670		} else if (typeOf(uriB) === "object") {
671			uriB = URI.serialize(uriB, options);
672		}
673
674		return uriA === uriB;
675	};
676
677	/**
678	 * @param {string} str
679	 * @returns {string}
680	 */
681
682	URI.escapeComponent = function (str) {
683		return str && str.toString().replace(ESCAPE, pctEncChar);
684	};
685
686	/**
687	 * @param {string} str
688	 * @returns {string}
689	 */
690
691	URI.unescapeComponent = function (str) {
692		return str && str.toString().replace(PCT_ENCODEDS, pctDecChars);
693	};
694
695	//export API
696	exports.Components = Components;
697	exports.URI = URI;
698
699	//name-safe export API
700	exports["URI"] = {
701		"SCHEMES" : URI.SCHEMES,
702		"parse" : URI.parse,
703		"removeDotSegments" : URI.removeDotSegments,
704		"serialize" : URI.serialize,
705		"resolveComponents" : URI.resolveComponents,
706		"resolve" : URI.resolve,
707		"normalize" : URI.normalize,
708		"equal" : URI.equal,
709		"escapeComponent" : URI.escapeComponent,
710		"unescapeComponent" : URI.unescapeComponent
711	};
712
713}());
714
715
716
717	/**
718 * JSV: JSON Schema Validator
719 * 
720 * @fileOverview A JavaScript implementation of a extendable, fully compliant JSON Schema validator.
721 * @author <a href="mailto:[email protected]">Gary Court</a>
722 * @version 3.5
723 * @see http://github.com/garycourt/JSV
724 */
725
726/*
727 * Copyright 2010 Gary Court. All rights reserved.
728 * 
729 * Redistribution and use in source and binary forms, with or without modification, are
730 * permitted provided that the following conditions are met:
731 * 
732 *    1. Redistributions of source code must retain the above copyright notice, this list of
733 *       conditions and the following disclaimer.
734 * 
735 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
736 *       of conditions and the following disclaimer in the documentation and/or other materials
737 *       provided with the distribution.
738 * 
739 * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
740 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
741 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
742 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
743 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
744 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
745 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
746 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
747 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
748 * 
749 * The views and conclusions contained in the software and documentation are those of the
750 * authors and should not be interpreted as representing official policies, either expressed
751 * or implied, of Gary Court or the JSON Schema specification.
752 */
753
754/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
755
756var exports = exports || this,
757	require = require || function () {
758		return exports;
759	};
760
761(function () {
762
763	var URI = require("./uri/uri").URI,
764		O = {},
765		I2H = "0123456789abcdef".split(""),
766		mapArray, filterArray, searchArray,
767
768		JSV;
769
770	//
771	// Utility functions
772	//
773
774	function typeOf(o) {
775		return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
776	}
777
778	/** @inner */
779	function F() {}
780
781	function createObject(proto) {
782		F.prototype = proto || {};
783		return new F();
784	}
785
786	function mapObject(obj, func, scope) {
787		var newObj = {}, key;
788		for (key in obj) {
789			if (obj[key] !== O[key]) {
790				newObj[key] = func.call(scope, obj[key], key, obj);
791			}
792		}
793		return newObj;
794	}
795
796	/** @ignore */
797	mapArray = function (arr, func, scope) {
798		var x = 0, xl = arr.length, newArr = new Array(xl);
799		for (; x < xl; ++x) {
800			newArr[x] = func.call(scope, arr[x], x, arr);
801		}
802		return newArr;
803	};
804
805	if (Array.prototype.map) {
806		/** @ignore */
807		mapArray = function (arr, func, scope) {
808			return Array.prototype.map.call(arr, func, scope);
809		};
810	}
811
812	/** @ignore */
813	filterArray = function (arr, func, scope) {
814		var x = 0, xl = arr.length, newArr = [];
815		for (; x < xl; ++x) {
816			if (func.call(scope, arr[x], x, arr)) {
817				newArr[newArr.length] = arr[x];
818			}
819		}
820		return newArr;
821	};
822
823	if (Array.prototype.filter) {
824		/** @ignore */
825		filterArray = function (arr, func, scope) {
826			return Array.prototype.filter.call(arr, func, scope);
827		};
828	}
829
830	/** @ignore */
831	searchArray = function (arr, o) {
832		var x = 0, xl = arr.length;
833		for (; x < xl; ++x) {
834			if (arr[x] === o) {
835				return x;
836			}
837		}
838		return -1;
839	};
840
841	if (Array.prototype.indexOf) {
842		/** @ignore */
843		searchArray = function (arr, o) {
844			return Array.prototype.indexOf.call(arr, o);
845		};
846	}
847
848	function toArray(o) {
849		return o !== undefined && o !== null ? (o instanceof Array && !o.callee ? o : (typeof o.length !== "number" || o.split || o.setInterval || o.call ? [ o ] : Array.prototype.slice.call(o))) : [];
850	}
851
852	function keys(o) {
853		var result = [], key;
854
855		switch (typeOf(o)) {
856		case "object":
857			for (key in o) {
858				if (o[key] !== O[key]) {
859					result[result.length] = key;
860				}
861			}
862			break;
863		case "array":
864			for (key = o.length - 1; key >= 0; --key) {
865				result[key] = key;
866			}
867			break;
868		}
869
870		return result;
871	}
872
873	function pushUnique(arr, o) {
874		if (searchArray(arr, o) === -1) {
875			arr.push(o);
876		}
877		return arr;
878	}
879
880	function popFirst(arr, o) {
881		var index = searchArray(arr, o);
882		if (index > -1) {
883			arr.splice(index, 1);
884		}
885		return arr;
886	}
887
888	function randomUUID() {
889		return [
890			I2H[Math.floor(Math.random() * 0x10)],
891			I2H[Math.floor(Math.random() * 0x10)],
892			I2H[Math.floor(Math.random() * 0x10)],
893			I2H[Math.floor(Math.random() * 0x10)],
894			I2H[Math.floor(Math.random() * 0x10)],
895			I2H[Math.floor(Math.random() * 0x10)],
896			I2H[Math.floor(Math.random() * 0x10)],
897			I2H[Math.floor(Math.random() * 0x10)],
898			"-",
899			I2H[Math.floor(Math.random() * 0x10)],
900			I2H[Math.floor(Math.random() * 0x10)],
901			I2H[Math.floor(Math.random() * 0x10)],
902			I2H[Math.floor(Math.random() * 0x10)],
903			"-4",  //set 4 high bits of time_high field to version
904			I2H[Math.floor(Math.random() * 0x10)],
905			I2H[Math.floor(Math.random() * 0x10)],
906			I2H[Math.floor(Math.random() * 0x10)],
907			"-",
908			I2H[(Math.floor(Math.random() * 0x10) & 0x3) | 0x8],  //specify 2 high bits of clock sequence
909			I2H[Math.floor(Math.random() * 0x10)],
910			I2H[Math.floor(Math.random() * 0x10)],
911			I2H[Math.floor(Math.random() * 0x10)],
912			"-",
913			I2H[Math.floor(Math.random() * 0x10)],
914			I2H[Math.floor(Math.random() * 0x10)],
915			I2H[Math.floor(Math.random() * 0x10)],
916			I2H[Math.floor(Math.random() * 0x10)],
917			I2H[Math.floor(Math.random() * 0x10)],
918			I2H[Math.floor(Math.random() * 0x10)],
919			I2H[Math.floor(Math.random() * 0x10)],
920			I2H[Math.floor(Math.random() * 0x10)],
921			I2H[Math.floor(Math.random() * 0x10)],
922			I2H[Math.floor(Math.random() * 0x10)],
923			I2H[Math.floor(Math.random() * 0x10)],
924			I2H[Math.floor(Math.random() * 0x10)]
925		].join("");
926	}
927
928	function escapeURIComponent(str) {
929		return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
930	}
931
932	function formatURI(uri) {
933		if (typeof uri === "string" && uri.indexOf("#") === -1) {
934			uri += "#";
935		}
936		return uri;
937	}
938
939	/**
940	 * Defines an error, found by a schema, with an instance.
941	 * This class can only be instantiated by {@link Report#addError}. 
942	 * 
943	 * @name ValidationError
944	 * @class
945	 * @see Report#addError
946	 */
947
948	/**
949	 * The URI of the instance that has the error.
950	 * 
951	 * @name ValidationError.prototype.uri
952	 * @type String
953	 */
954
955	/**
956	 * The URI of the schema that generated the error.
957	 * 
958	 * @name ValidationError.prototype.schemaUri
959	 * @type String
960	 */
961
962	/**
963	 * The name of the schema attribute that generated the error.
964	 * 
965	 * @name ValidationError.prototype.attribute
966	 * @type String
967	 */
968
969	/**
970	 * An user-friendly (English) message about what failed to validate.
971	 * 
972	 * @name ValidationError.prototype.message
973	 * @type String
974	 */
975
976	/**
977	 * The value of the schema attribute that generated the error.
978	 * 
979	 * @name ValidationError.prototype.details
980	 * @type Any
981	 */
982
983	/**
984	 * Reports are returned from validation methods to describe the result of a validation.
985	 * 
986	 * @name Report
987	 * @class
988	 * @see JSONSchema#validate
989	 * @see Environment#validate
990	 */
991
992	function Report() {
993		/**
994		 * An array of {@link ValidationError} objects that define all the errors generated by the schema against the instance.
995		 * 
996		 * @name Report.prototype.errors
997		 * @type Array
998		 * @see Report#addError
999		 */
1000		this.errors = [];
1001
1002		/**
1003		 * A hash table of every instance and what schemas were validated against it.
1004		 * <p>
1005		 * The key of each item in the table is the URI of the instance that was validated.
1006		 * The value of this key is an array of strings of URIs of the schema that validated it.
1007		 * </p>
1008		 * 
1009		 * @name Report.prototype.validated
1010		 * @type Object
1011		 * @see Report#registerValidation
1012		 * @see Report#isValidatedBy
1013		 */
1014		this.validated = {};
1015
1016		/**
1017		 * If the report is generated by {@link Environment#validate}, this field is the generated instance.
1018		 * 
1019		 * @name Report.prototype.instance
1020		 * @type JSONInstance
1021		 * @see Environment#validate
1022		 */
1023
1024		/**
1025		 * If the report is generated by {@link Environment#validate}, this field is the generated schema.
1026		 * 
1027		 * @name Report.prototype.schema
1028		 * @type JSONSchema
1029		 * @see Environment#validate
1030		 */
1031
1032		/**
1033		 * If the report is generated by {@link Environment#validate}, this field is the schema's schema.
1034		 * This value is the same as calling <code>schema.getSchema()</code>.
1035		 * 
1036		 * @name Report.prototype.schemaSchema
1037		 * @type JSONSchema
1038		 * @see Environment#validate
1039		 * @see JSONSchema#getSchema
1040		 */
1041	}
1042
1043	/**
1044	 * Adds a {@link ValidationError} object to the <a href="#errors"><code>errors</code></a> field.
1045	 * 
1046	 * @param {JSONInstance|String} instance The instance (or instance URI) that is invalid
1047	 * @param {JSONSchema|String} schema The schema (or schema URI) that was validating the instance
1048	 * @param {String} attr The attribute that failed to validated
1049	 * @param {String} message A user-friendly message on why the schema attribute failed to validate the instance
1050	 * @param {Any} details The value of the schema attribute
1051	 */
1052
1053	Report.prototype.addError = function (instance, schema, attr, message, details) {
1054		this.errors.push({
1055			uri : instance instanceof JSONInstance ? instance.getURI() : instance,
1056			schemaUri : schema instanceof JSONInstance ? schema.getURI() : schema,
1057			attribute : attr,
1058			message : message,
1059			details : details
1060		});
1061	};
1062
1063	/**
1064	 * Registers that the provided instance URI has been validated by the provided schema URI. 
1065	 * This is recorded in the <a href="#validated"><code>validated</code></a> field.
1066	 * 
1067	 * @param {String} uri The URI of the instance that was validated
1068	 * @param {String} schemaUri The URI of the schema that validated the instance
1069	 */
1070
1071	Report.prototype.registerValidation = function (uri, schemaUri) {
1072		if (!this.validated[uri]) {
1073			this.validated[uri] = [ schemaUri ];
1074		} else {
1075			this.validated[uri].push(schemaUri);
1076		}
1077	};
1078
1079	/**
1080	 * Returns if an instance with the provided URI has been validated by the schema with the provided URI. 
1081	 * 
1082	 * @param {String} uri The URI of the instance
1083	 * @param {String} schemaUri The URI of a schema
1084	 * @returns {Boolean} If the instance has been validated by the schema.
1085	 */
1086
1087	Report.prototype.isValidatedBy = function (uri, schemaUri) {
1088		return !!this.validated[uri] && searchArray(this.validated[uri], schemaUri) !== -1;
1089	};
1090
1091	/**
1092	 * A wrapper class for binding an Environment, URI and helper methods to an instance. 
1093	 * This class is most commonly instantiated with {@link Environment#createInstance}.
1094	 * 
1095	 * @name JSONInstance
1096	 * @class
1097	 * @param {Environment} env The environment this instance belongs to
1098	 * @param {JSONInstance|Any} json The value of the instance
1099	 * @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID. 
1100	 * @param {String} [fd] The fragment delimiter for properties. If undefined, uses the environment default.
1101	 */
1102
1103	function JSONInstance(env, json, uri, fd) {
1104		if (json instanceof JSONInstance) {
1105			if (typeof fd !== "string") {
1106				fd = json._fd;
1107			}
1108			if (typeof uri !== "string") {
1109				uri = json._uri;
1110			}
1111			json = json._value;
1112		}
1113
1114		if (typeof uri !== "string") {
1115			uri = "urn:uuid:" + randomUUID() + "#";
1116		} else if (uri.indexOf(":") === -1) {
1117			uri = formatURI(URI.resolve("urn:uuid:" + randomUUID() + "#", uri));
1118		}
1119
1120		this._env = env;
1121		this._value = json;
1122		this._uri = uri;
1123		this._fd = fd || this._env._options["defaultFragmentDelimiter"];
1124	}
1125
1126	/**
1127	 * Returns the environment the instance is bound to.
1128	 * 
1129	 * @returns {Environment} The environment of the instance
1130	 */
1131
1132	JSONInstance.prototype.getEnvironment = function () {
1133		return this._env;
1134	};
1135
1136	/**
1137	 * Returns the name of the type of the instance.
1138	 * 
1139	 * @returns {String} The name of the type of the instance
1140	 */
1141
1142	JSONInstance.prototype.getType = function () {
1143		return typeOf(this._value);
1144	};
1145
1146	/**
1147	 * Returns the JSON value of the instance.
1148	 * 
1149	 * @returns {Any} The actual JavaScript value of the instance
1150	 */
1151
1152	JSONInstance.prototype.getValue = function () {
1153		return this._value;
1154	};
1155
1156	/**
1157	 * Returns the URI of the instance.
1158	 * 
1159	 * @returns {String} The URI of the instance
1160	 */
1161
1162	JSONInstance.prototype.getURI = function () {
1163		return this._uri;
1164	};
1165
1166	/**
1167	 * Returns a resolved URI of a provided relative URI against the URI of the instance.
1168	 * 
1169	 * @param {String} uri The relative URI to resolve
1170	 * @returns {String} The resolved URI
1171	 */
1172
1173	JSONInstance.prototype.resolveURI = function (uri) {
1174		return formatURI(URI.resolve(this._uri, uri));
1175	};
1176
1177	/**
1178	 * Returns an array of the names of all the properties.
1179	 * 
1180	 * @returns {Array}
1180 An array of strings which are the names of all the properties
1181	 */
1182
1183	JSONInstance.prototype.getPropertyNames = function () {
1184		return keys(this._value);
1185	};
1186
1187	/**
1188	 * Returns a {@link JSONInstance} of the value of the provided property name. 
1189	 * 
1190	 * @param {String} key The name of the property to fetch
1191	 * @returns {JSONInstance} The instance of the property value
1192	 */
1193
1194	JSONInstance.prototype.getProperty = function (key) {
1195		var value = this._value ? this._value[key] : undefined;
1196		if (value instanceof JSONInstance) {
1197			return value;
1198		}
1199		//else
1200		return new JSONInstance(this._env, value, this._uri + this._fd + escapeURIComponent(key), this._fd);
1201	};
1202
1203	/**
1204	 * Returns all the property instances of the target instance.
1205	 * <p>
1206	 * If the target instance is an Object, then the method will return a hash table of {@link JSONInstance}s of all the properties. 
1207	 * If the target instance is an Array, then the method will return an array of {@link JSONInstance}s of all the items.
1208	 * </p> 
1209	 * 
1210	 * @returns {Object|Array|undefined} The list of instances for all the properties
1211	 */
1212
1213	JSONInstance.prototype.getProperties = function () {
1214		var type = typeOf(this._value),
1215			self = this;
1216
1217		if (type === "object") {
1218			return mapObject(this._value, function (value, key) {
1219				if (value instanceof JSONInstance) {
1220					return value;
1221				}
1222				return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
1223			});
1224		} else if (type === "array") {
1225			return mapArray(this._value, function (value, key) {
1226				if (value instanceof JSONInstance) {
1227					return value;
1228				}
1229				return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
1230			});
1231		}
1232	};
1233
1234	/**
1235	 * Returns the JSON value of the provided property name. 
1236	 * This method is a faster version of calling <code>instance.getProperty(key).getValue()</code>.
1237	 * 
1238	 * @param {String} key The name of the property
1239	 * @returns {Any} The JavaScript value of the instance
1240	 * @see JSONInstance#getProperty
1241	 * @see JSONInstance#getValue
1242	 */
1243
1244	JSONInstance.prototype.getValueOfProperty = function (key) {
1245		if (this._value) {
1246			if (this._value[key] instanceof JSONInstance) {
1247				return this._value[key]._value;
1248			}
1249			return this._value[key];
1250		}
1251	};
1252
1253	/**
1254	 * Return if the provided value is the same as the value of the instance.
1255	 * 
1256	 * @param {JSONInstance|Any} instance The value to compare
1257	 * @returns {Boolean} If both the instance and the value match
1258	 */
1259
1260	JSONInstance.prototype.equals = function (instance) {
1261		if (instance instanceof JSONInstance) {
1262			return this._value === instance._value;
1263		}
1264		//else
1265		return this._value === instance;
1266	};
1267
1268	/**
1269	 * Warning: Not a generic clone function
1270	 * Produces a JSV acceptable clone
1271	 */
1272
1273	function clone(obj, deep) {
1274		var newObj, x;
1275
1276		if (obj instanceof JSONInstance) {
1277			obj = obj.getValue();
1278		}
1279
1280		switch (typeOf(obj)) {
1281		case "object":
1282			if (deep) {
1283				newObj = {};
1284				for (x in obj) {
1285					if (obj[x] !== O[x]) {
1286						newObj[x] = clone(obj[x], deep);
1287					}
1288				}
1289				return newObj;
1290			} else {
1291				return createObject(obj);
1292			}
1293			break;
1294		case "array":
1295			if (deep) {
1296				newObj = new Array(obj.length);
1297				x = obj.length;
1298				while (--x >= 0) {
1299					newObj[x] = clone(obj[x], deep);
1300				}
1301				return newObj;
1302			} else {
1303				return Array.prototype.slice.call(obj);
1304			}
1305			break;
1306		default:
1307			return obj;
1308		}
1309	}
1310
1311	/**
1312	 * This class binds a {@link JSONInstance} with a {@link JSONSchema} to provided context aware methods. 
1313	 * 
1314	 * @name JSONSchema
1315	 * @class
1316	 * @param {Environment} env The environment this schema belongs to
1317	 * @param {JSONInstance|Any} json The value of the schema
1318	 * @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID. 
1319	 * @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
1320	 * @extends JSONInstance
1321	 */
1322
1323	function JSONSchema(env, json, uri, schema) {
1324		var fr;
1325		JSONInstance.call(this, env, json, uri);
1326
1327		if (schema === true) {
1328			this._schema = this;
1329		} else if (json instanceof JSONSchema && !(schema instanceof JSONSchema)) {
1330			this._schema = json._schema;  //TODO: Make sure cross environments don't mess everything up
1331		} else {
1332			this._schema = schema instanceof JSONSchema ? schema : this._env.getDefaultSchema() || JSONSchema.createEmptySchema(this._env);
1333		}
1334
1335		//determine fragment delimiter from schema
1336		fr = this._schema.getValueOfProperty("fragmentResolution");
1337		if (fr === "dot-delimited") {
1338			this._fd = ".";
1339		} else if (fr === "slash-delimited") {
1340			this._fd = "/";
1341		}
1342	}
1343
1344	JSONSchema.prototype = createObject(JSONInstance.prototype);
1345
1346	/**
1347	 * Creates an empty schema.
1348	 * 
1349	 * @param {Environment} env The environment of the schema
1350	 * @returns {JSONSchema} The empty schema, who's schema is itself.
1351	 */
1352
1353	JSONSchema.createEmptySchema = function (env) {
1354		var schema = createObject(JSONSchema.prototype);
1355		JSONInstance.call(schema, env, {}, undefined, undefined);
1356		schema._schema = schema;
1357		return schema;
1358	};
1359
1360	/**
1361	 * Returns the schema of the schema.
1362	 * 
1363	 * @returns {JSONSchema} The schema of the schema
1364	 */
1365
1366	JSONSchema.prototype.getSchema = function () {
1367		return this._schema;
1368	};
1369
1370	/**
1371	 * Returns the value of the provided attribute name.
1372	 * <p>
1373	 * This method is different from {@link JSONInstance#getProperty} as the named property 
1374	 * is converted using a parser defined by the schema's schema before being returned. This
1375	 * makes the return value of this method attribute dependent.
1376	 * </p>
1377	 * 
1378	 * @param {String} key The name of the attribute
1379	 * @param {Any} [arg] Some attribute parsers accept special arguments for returning resolved values. This is attribute dependent.
1380	 * @returns {JSONSchema|Any} The value of the attribute
1381	 */
1382
1383	JSONSchema.prototype.getAttribute = function (key, arg) {
1384		var schemaProperty, parser, property, result;
1385
1386		if (!arg && this._attributes && this._attributes.hasOwnProperty(key)) {
1387			return this._attributes[key];
1388		}
1389
1390		schemaProperty = this._schema.getProperty("properties").getProperty(key);
1391		parser = schemaProperty.getValueOfProperty("parser");
1392		property = this.getProperty(key);
1393		if (typeof parser === "function") {
1394			result = parser(property, schemaProperty, arg);
1395			if (!arg && this._attributes) {
1396				this._attributes[key] = result;
1397			}
1398			return result;
1399		}
1400		//else
1401		return property.getValue();
1402	};
1403
1404	/**
1405	 * Returns all the attributes of the schema.
1406	 * 
1407	 * @returns {Object} A map of all parsed attribute values
1408	 */
1409
1410	JSONSchema.prototype.getAttributes = function () {
1411		var properties, schemaProperties, key, schemaProperty, parser;
1412
1413		if (!this._attributes && this.getType() === "object") {
1414			properties = this.getProperties();
1415			schemaProperties = this._schema.getProperty("properties");
1416			this._attributes = {};
1417			for (key in properties) {
1418				if (properties[key] !== O[key]) {
1419					schemaProperty = schemaProperties && schemaProperties.getProperty(key);
1420					parser = schemaProperty && schemaProperty.getValueOfProperty("parser");
1421					if (typeof parser === "function") {
1422						this._attributes[key] = parser(properties[key], schemaProperty);
1423					} else {
1424						this._attributes[key] = properties[key].getValue();
1425					}
1426				}
1427			}
1428		}
1429
1430		return clone(this._attributes, false);
1431	};
1432
1433	/**
1434	 * Convenience method for retrieving a link or link object from a schema. 
1435	 * This method is the same as calling <code>schema.getAttribute("links", [rel, instance])[0];</code>.
1436	 * 
1437	 * @param {String} rel The link relationship
1438	 * @param {JSONInstance} [instance] The instance to resolve any URIs from
1439	 * @returns {String|Object|undefined} If <code>instance</code> is provided, a string containing the resolve URI of the link is returned.
1440	 *   If <code>instance</code> is not provided, a link object is returned with details of the link.
1441	 *   If no link with the provided relationship exists, <code>undefined</code> is returned.
1442	 * @see JSONSchema#getAttribute
1443	 */
1444
1445	JSONSchema.prototype.getLink = function (rel, instance) {
1446		var schemaLinks = this.getAttribute("links", [rel, instance]);
1447		if (schemaLinks && schemaLinks.length && schemaLinks[schemaLinks.length - 1]) {
1448			return schemaLinks[schemaLinks.length - 1];
1449		}
1450	};
1451
1452	/**
1453	 * Validates the provided instance against the target schema and returns a {@link Report}.
1454	 * 
1455	 * @param {JSONInstance|Any} instance The instance to validate; may be a {@link JSONInstance} or any JavaScript value
1456	 * @param {Report} [report] A {@link Report} to concatenate the result of the validation to. If <code>undefined</code>, a new {@link Report} is created. 
1457	 * @param {JSONInstance} [parent] The parent/containing instance of the provided instance
1458	 * @param {JSONSchema} [parentSchema] The schema of the parent/containing instance
1459	 * @param {String} [name] The name of the parent object's property that references the instance
1460	 * @returns {Report} The result of the validation
1461	 */
1462
1463	JSONSchema.prototype.validate = function (instance, report, parent, parentSchema, name) {
1464		var validator = this._schema.getValueOfProperty("validator");
1465
1466		if (!(instance instanceof JSONInstance)) {
1467			instance = this.getEnvironment().createInstance(instance);
1468		}
1469
1470		if (!(report instanceof Report)) {
1471			report = new Report();
1472		}
1473
1474		if (typeof validator === "function" && !report.isValidatedBy(instance.getURI(), this.getURI())) {
1475			report.registerValidation(instance.getURI(), this.getURI());
1476			validator(instance, this, this._schema, report, parent, parentSchema, name);
1477		}
1478
1479		return report;
1480	};
1481
1482	/**
1483	 * Merges two schemas/instances together.
1484	 */
1485
1486	function inherits(base, extra, extension) {
1487		var baseType = typeOf(base),
1488			extraType = typeOf(extra),
1489			child, x;
1490
1491		if (extraType === "undefined") {
1492			return clone(base, true);
1493		} else if (baseType === "undefined" || extraType !== baseType) {
1494			return clone(extra, true);
1495		} else if (extraType === "object") {
1496			if (base instanceof JSONSchema) {
1497				base = base.getAttributes();
1498			}
1499			if (extra instanceof JSONSchema) {
1500				extra = extra.getAttributes();
1501				if (extra["extends"] && extension && extra["extends"] instanceof JSONSchema) {
1502					extra["extends"] = [ extra["extends"] ];
1503				}
1504			}
1505			child = clone(base, true);  //this could be optimized as some properties get overwritten
1506			for (x in extra) {
1507				if (extra[x] !== O[x]) {
1508					child[x] = inherits(base[x], extra[x], extension);
1509				}
1510			}
1511			return child;
1512		} else {
1513			return clone(extra, true);
1514		}
1515	}
1516
1517	/**
1518	 * An Environment is a sandbox of schemas thats behavior is different from other environments.
1519	 * 
1520	 * @name Environment
1521	 * @class
1522	 */
1523
1524	function Environment() {
1525		this._id = randomUUID();
1526		this._schemas = {};
1527		this._options = {};
1528	}
1529
1530	/**
1531	 * Returns a clone of the target environment.
1532	 * 
1533	 * @returns {Environment} A new {@link Environment} that is a exact copy of the target environment 
1534	 */
1535
1536	Environment.prototype.clone = function () {
1537		var env = new Environment();
1538		env._schemas = createObject(this._schemas);
1539		env._options = createObject(this._options);
1540
1541		return env;
1542	};
1543
1544	/**
1545	 * Returns a new {@link JSONInstance} of the provided data.
1546	 * 
1547	 * @param {JSONInstance|Any} data The value of the instance
1548	 * @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID. 
1549	 * @returns {JSONInstance} A new {@link JSONInstance} from the provided data
1550	 */
1551
1552	Environment.prototype.createInstance = function (data, uri) {
1553		var instance;
1554		uri = formatURI(uri);
1555
1556		if (data instanceof JSONInstance && (!uri || data.getURI() === uri)) {
1557			return data;
1558		}
1559		//else
1560		instance = new JSONInstance(this, data, uri);
1561
1562		return instance;
1563	};
1564
1565	/**
1566	 * Creates a new {@link JSONSchema} from the provided data, and registers it with the environment. 
1567	 * 
1568	 * @param {JSONInstance|Any} data The value of the schema
1569	 * @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
1570	 * @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID. 
1571	 * @returns {JSONSchema} A new {@link JSONSchema} from the provided data
1572	 * @throws {InitializationError} If a schema that is not registered with the environment is referenced 
1573	 */
1574
1575	Environment.prototype.createSchema = function (data, schema, uri) {
1576		var instance, 
1577			initializer;
1578		uri = formatURI(uri);
1579
1580		if (data instanceof JSONSchema && (!uri || data._uri === uri) && (!schema || data._schema.equals(schema))) {
1581			return data;
1582		}
1583
1584		instance = new JSONSchema(this, data, uri, schema);
1585
1586		initializer = instance.getSchema().getValueOfProperty("initializer");
1587		if (typeof initializer === "function") {
1588			instance = initializer(instance);
1589		}
1590
1591		//register schema
1592		this._schemas[instance._uri] = instance;
1593		this._schemas[uri] = instance;
1594
1595		//build & cache the rest of the schema
1596		instance.getAttributes();
1597
1598		return instance;
1599	};
1600
1601	/**
1602	 * Creates an empty schema.
1603	 * 
1604	 * @param {Environment} env The environment of the schema
1605	 * @returns {JSONSchema}
1605 The empty schema, who's schema is itself.
1606	 */
1607
1608	Environment.prototype.createEmptySchema = function () {
1609		var schema = JSONSchema.createEmptySchema(this);
1610		this._schemas[schema._uri] = schema;
1611		return schema;
1612	};
1613
1614	/**
1615	 * Returns the schema registered with the provided URI.
1616	 * 
1617	 * @param {String} uri The absolute URI of the required schema
1618	 * @returns {JSONSchema|undefined} The request schema, or <code>undefined</code> if not found
1619	 */
1620
1621	Environment.prototype.findSchema = function (uri) {
1622		return this._schemas[formatURI(uri)];
1623	};
1624
1625	/**
1626	 * Sets the specified environment option to the specified value.
1627	 * 
1628	 * @param {String} name The name of the environment option to set
1629	 * @param {Any} value The new value of the environment option
1630	 */
1631
1632	Environment.prototype.setOption = function (name, value) {
1633		this._options[name] = value;
1634	};
1635
1636	/**
1637	 * Returns the specified environment option.
1638	 * 
1639	 * @param {String} name The name of the environment option to set
1640	 * @returns {Any} The value of the environment option
1641	 */
1642
1643	Environment.prototype.getOption = function (name) {
1644		return this._options[name];
1645	};
1646
1647	/**
1648	 * Sets the default fragment delimiter of the environment.
1649	 * 
1650	 * @deprecated Use {@link Environment#setOption} with option "defaultFragmentDelimiter"
1651	 * @param {String} fd The fragment delimiter character
1652	 */
1653
1654	Environment.prototype.setDefaultFragmentDelimiter = function (fd) {
1655		if (typeof fd === "string" && fd.length > 0) {
1656			this._options["defaultFragmentDelimiter"] = fd;
1657		}
1658	};
1659
1660	/**
1661	 * Returns the default fragment delimiter of the environment.
1662	 * 
1663	 * @deprecated Use {@link Environment#getOption} with option "defaultFragmentDelimiter"
1664	 * @returns {String} The fragment delimiter character
1665	 */
1666
1667	Environment.prototype.getDefaultFragmentDelimiter = function () {
1668		return this._options["defaultFragmentDelimiter"];
1669	};
1670
1671	/**
1672	 * Sets the URI of the default schema for the environment.
1673	 * 
1674	 * @deprecated Use {@link Environment#setOption} with option "defaultSchemaURI"
1675	 * @param {String} uri The default schema URI
1676	 */
1677
1678	Environment.prototype.setDefaultSchemaURI = function (uri) {
1679		if (typeof uri === "string") {
1680			this._options["defaultSchemaURI"] = formatURI(uri);
1681		}
1682	};
1683
1684	/**
1685	 * Returns the default schema of the environment.
1686	 * 
1687	 * @returns {JSONSchema} The default schema
1688	 */
1689
1690	Environment.prototype.getDefaultSchema = function () {
1691		return this.findSchema(this._options["defaultSchemaURI"]);
1692	};
1693
1694	/**
1695	 * Validates both the provided schema and the provided instance, and returns a {@link Report}. 
1696	 * If the schema fails to validate, the instance will not be validated.
1697	 * 
1698	 * @param {JSONInstance|Any} instanceJSON The {@link JSONInstance} or JavaScript value to validate.
1699	 * @param {JSONSchema|Any} schemaJSON The {@link JSONSchema} or JavaScript value to use in the validation. This will also be validated againt the schema's schema.
1700	 * @returns {Report} The result of the validation
1701	 */
1702
1703	Environment.prototype.validate = function (instanceJSON, schemaJSON) {
1704		var instance,
1705			schema,
1706			schemaSchema,
1707			report = new Report();
1708
1709		try {
1710			instance = this.createInstance(instanceJSON);
1711			report.instance = instance;
1712		} catch (e) {
1713			report.addError(e.uri, e.schemaUri, e.attribute, e.message, e.details);
1714		}
1715
1716		try {
1717			schema = this.createSchema(schemaJSON);
1718			report.schema = schema;
1719
1720			schemaSchema = schema.getSchema();
1721			report.schemaSchema = schemaSchema;
1722		} catch (e) {
1723			report.addError(e.uri, e.schemaUri, e.attribute, e.message, e.details);
1724		}
1725
1726		if (schemaSchema) {
1727			schemaSchema.validate(schema, report);
1728		}
1729
1730		if (report.errors.length) {
1731			return report;
1732		}
1733
1734		return schema.validate(instance, report);
1735	};
1736
1737	/**
1738	 * @private
1739	 */
1740
1741	Environment.prototype._checkForInvalidInstances = function (stackSize, schemaURI) {
1742		var result = [],
1743			stack = [
1744				[schemaURI, this._schemas[schemaURI]]
1745			], 
1746			counter = 0,
1747			item, uri, instance, schema, properties, key;
1748
1749		while (counter++ < stackSize && stack.length) {
1750			item = stack.shift();
1751			uri = item[0];
1752			instance = item[1];
1753
1754			if (instance instanceof JSONSchema) {
1755				if (this._schemas[instance._uri] !== instance) {
1756					result.push("Instance " + uri + " does not match " + instance._uri);
1757				} else {
1758					//schema = instance.getSchema();
1759					//stack.push([uri + "/{schema}", schema]);
1760
1761					properties = instance.getAttributes();
1762					for (key in properties) {
1763						if (properties[key] !== O[key]) {
1764							stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
1765						}
1766					}
1767				}
1768			} else if (typeOf(instance) === "object") {
1769				properties = instance;
1770				for (key in properties) {
1771					if (properties.hasOwnProperty(key)) {
1772						stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
1773					}
1774				}
1775			} else if (typeOf(instance) === "array") {
1776				properties = instance;
1777				for (key = 0; key < properties.length; ++key) {
1778					stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
1779				}
1780			}
1781		}
1782
1783		return result.length ? result : counter;
1784	};
1785
1786	/**
1787	 * A globaly accessible object that provides the ability to create and manage {@link Environments},
1788	 * as well as providing utility methods.
1789	 * 
1790	 * @namespace
1791	 */
1792
1793	JSV = {
1794		_environments : {},
1795		_defaultEnvironmentID : "",
1796
1797		/**
1798		 * Returns if the provide value is an instance of {@link JSONInstance}.
1799		 * 
1800		 * @param o The value to test
1801		 * @returns {Boolean} If the provide value is an instance of {@link JSONInstance}
1802		 */
1803
1804		isJSONInstance : function (o) {
1805			return o instanceof JSONInstance;
1806		},
1807
1808		/**
1809		 * Returns if the provide value is an instance of {@link JSONSchema}.
1810		 * 
1811		 * @param o The value to test
1812		 * @returns {Boolean} If the provide value is an instance of {@link JSONSchema}
1813		 */
1814
1815		isJSONSchema : function (o) {
1816			return o instanceof JSONSchema;
1817		},
1818
1819		/**
1820		 * Creates and returns a new {@link Environment} that is a clone of the environment registered with the provided ID.
1821		 * If no environment ID is provided, the default environment is cloned.
1822		 * 
1823		 * @param {String} [id] The ID of the environment to clone. If <code>undefined</code>, the default environment ID is used.
1824		 * @returns {Environment} A newly cloned {@link Environment}
1825		 * @throws {Error} If there is no environment registered with the provided ID
1826		 */
1827
1828		createEnvironment : function (id) {
1829			id = id || this._defaultEnvironmentID;
1830
1831			if (!this._environments[id]) {
1832				throw new Error("Unknown Environment ID");
1833			}
1834			//else
1835			return this._environments[id].clone();
1836		},
1837
1838		Environment : Environment,
1839
1840		/**
1841		 * Registers the provided {@link Environment} with the provided ID.
1842		 * 
1843		 * @param {String} id The ID of the environment
1844		 * @param {Environment} env The environment to register
1845		 */
1846
1847		registerEnvironment : function (id, env) {
1848			id = id || (env || 0)._id;
1849			if (id && !this._environments[id] && env instanceof Environment) {
1850				env._id = id;
1851				this._environments[id] = env;
1852			}
1853		},
1854
1855		/**
1856		 * Sets which registered ID is the default environment.
1857		 * 
1858		 * @param {String} id The ID of the registered environment that is default
1859		 * @throws {Error} If there is no registered environment with the provided ID
1860		 */
1861
1862		setDefaultEnvironmentID : function (id) {
1863			if (typeof id === "string") {
1864				if (!this._environments[id]) {
1865					throw new Error("Unknown Environment ID");
1866				}
1867
1868				this._defaultEnvironmentID = id;
1869			}
1870		},
1871
1872		/**
1873		 * Returns the ID of the default environment.
1874		 * 
1875		 * @returns {String} The ID of the default environment
1876		 */
1877
1878		getDefaultEnvironmentID : function () {
1879			return this._defaultEnvironmentID;
1880		},
1881
1882		//
1883		// Utility Functions
1884		//
1885
1886		/**
1887		 * Returns the name of the type of the provided value.
1888		 *
1889		 * @event //utility
1890		 * @param {Any} o The value to determine the type of
1891		 * @returns {String} The name of the type of the value
1892		 */
1893		typeOf : typeOf,
1894
1895		/**
1896		 * Return a new object that inherits all of the properties of the provided object.
1897		 *
1898		 * @event //utility
1899		 * @param {Object} proto The prototype of the new object
1900		 * @returns {Object} A new object that inherits all of the properties of the provided object
1901		 */
1902		createObject : createObject,
1903
1904		/**
1905		 * Returns a new object with each property transformed by the iterator.
1906		 *
1907		 * @event //utility
1908		 * @param {Object} obj The object to transform
1909		 * @param {Function} iterator A function that returns the new value of the provided property
1910		 * @param {Object} [scope] The value of <code>this</code> in the iterator
1911		 * @returns {Object} A new object with each property transformed
1912		 */
1913		mapObject : mapObject,
1914
1915		/**
1916		 * Returns a new array with each item transformed by the iterator.
1917		 * 
1918		 * @event //utility
1919		 * @param {Array} arr The array to transform
1920		 * @param {Function} iterator A function that returns the new value of the provided item
1921		 * @param {Object} scope The value of <code>this</code> in the iterator
1922		 * @returns {Array} A new array with each item transformed
1923		 */
1924		mapArray : mapArray,
1925
1926		/**
1927		 * Returns a new array that only contains the items allowed by the iterator.
1928		 *
1929		 * @event //utility
1930		 * @param {Array} arr The array to filter
1931		 * @param {Function} iterator The function that returns true if the provided property should be added to the array
1932		 * @param {Object} scope The value of <code>this</code> within the iterator
1933		 * @returns {Array} A new array that contains the items allowed by the iterator
1934		 */
1935		filterArray : filterArray,
1936
1937		/**
1938		 * Returns the first index in the array that the provided item is located at.
1939		 *
1940		 * @event //utility
1941		 * @param {Array} arr The array to search
1942		 * @param {Any} o The item being searched for
1943		 * @returns {Number} The index of the item in the array, or <code>-1</code> if not found
1944		 */
1945		searchArray : searchArray,
1946
1947		/**
1948		 * Returns an array representation of a value.
1949		 * <ul>
1950		 * <li>For array-like objects, the value will be casted as an Array type.</li>
1951		 * <li>If an array is provided, the function will simply return the same array.</li>
1952		 * <li>For a null or undefined value, the result will be an empty Array.</li>
1953		 * <li>For all other values, the value will be the first element in a new Array. </li>
1954		 * </ul>
1955		 *
1956		 * @event //utility
1957		 * @param {Any} o The value to convert into an array
1958		 * @returns {Array} The value as an array
1959		 */
1960		toArray : toArray,
1961
1962		/**
1963		 * Returns an array of the names of all properties of an object.
1964		 * 
1965		 * @event //utility
1966		 * @param {Object|Array} o The object in question
1967		 * @returns {Array} The names of all properties
1968		 */
1969		keys : keys,
1970
1971		/**
1972		 * Mutates the array by pushing the provided value onto the array only if it is not already there.
1973		 *
1974		 * @event //utility
1975		 * @param {Array} arr The array to modify
1976		 * @param {Any} o The object to add to the array if it is not already there
1977		 * @returns {Array} The provided array for chaining
1978		 */
1979		pushUnique : pushUnique,
1980
1981		/**
1982		 * Mutates the array by removing the first item that matches the provided value in the array.
1983		 *
1984		 * @event //utility
1985		 * @param {Array} arr The array to modify
1986		 * @param {Any} o The object to remove from the array
1987		 * @returns {Array} The provided array for chaining
1988		 */
1989		popFirst : popFirst,
1990
1991		/**
1992		 * Creates a copy of the target object.
1993		 * <p>
1994		 * This method will create a new instance of the target, and then mixin the properties of the target.
1995		 * If <code>deep</code> is <code>true</code>, then each property will be cloned before mixin.
1996		 * </p>
1997		 * <p><b>Warning</b>: This is not a generic clone function, as it will only properly clone objects and arrays.</p>
1998		 * 
1999		 * @event //utility
2000		 * @param {Any} o The value to clone 
2001		 * @param {Boolean} [deep=false] If each property should be recursively cloned
2002		 * @returns A cloned copy of the provided value
2003		 */
2004		clone : clone,
2005
2006		/**
2007		 * Generates a pseudo-random UUID.
2008		 * 
2009		 * @event //utility
2010		 * @returns {String} A new universally unique ID
2011		 */
2012		randomUUID : randomUUID,
2013
2014		/**
2015		 * Properly escapes a URI component for embedding into a URI string.
2016		 * 
2017		 * @event //utility
2018		 * @param {String} str The URI component to escape
2019		 * @returns {String} The escaped URI component
2020		 */
2021		escapeURIComponent : escapeURIComponent,
2022
2023		/**
2024		 * Returns a URI that is formated for JSV. Currently, this only ensures that the URI ends with a hash tag (<code>#</code>).
2025		 * 
2026		 * @event //utility
2027		 * @param {String} uri The URI to format
2028		 * @returns {String} The URI formatted for JSV
2029		 */
2030		formatURI : formatURI,
2031
2032		/**
2033		 * Merges two schemas/instance together.
2034		 * 
2035		 * @event //utility
2036		 * @param {JSONSchema|Any} base The old value to merge
2037		 * @param {JSONSchema|Any} extra The new value to merge
2038		 * @param {Boolean} extension If the merge is a JSON Schema extension
2039		 * @return {Any} The modified base value
2040		 */
2041
2042		inherits : inherits
2043	};
2044
2045	this.JSV = JSV;  //set global object
2046	exports.JSV = JSV;  //export to CommonJS
2047
2048	require("./environments");  //load default environments
2049
2050}());
2051
2052
2053
2054
2055
2056/**
2057 * json-schema-draft-03 Environment
2058 * 
2059 * @fileOverview Implementation of the third revision of the JSON Schema specification draft.
2060 * @author <a href="mailto:[email protected]">Gary Court</a>
2061 * @version 1.3
2062 * @see http://github.com/garycourt/JSV
2063 */
2064
2065/*
2066 * Copyright 2010 Gary Court. All rights reserved.
2067 * 
2068 * Redistribution and use in source and binary forms, with or without modification, are
2069 * permitted provided that the following conditions are met:
2070 * 
2071 *    1. Redistributions of source code must retain the above copyright notice, this list of
2072 *       conditions and the following disclaimer.
2073 * 
2074 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
2075 *       of conditions and the following disclaimer in the documentation and/or other materials
2076 *       provided with the distribution.
2077 * 
2078 * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
2079 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2080 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
2081 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2082 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2083 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2084 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2085 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2086 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2087 * 
2088 * The views and conclusions contained in the software and documentation are those of the
2089 * authors and should not be interpreted as representing official policies, either expressed
2090 * or implied, of Gary Court or the JSON Schema specification.
2091 */
2092
2093/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
2094/*global require */
2095
2096(function () {
2097	var O = {},
2098		JSV = require('./jsv').JSV,
2099		InitializationError,
2100		TYPE_VALIDATORS,
2101		ENVIRONMENT,
2102		SCHEMA_00_JSON,
2103		HYPERSCHEMA_00_JSON,
2104		LINKS_00_JSON, 
2105		SCHEMA_00,
2106		HYPERSCHEMA_00,
2107		LINKS_00, 
2108		SCHEMA_01_JSON,
2109		HYPERSCHEMA_01_JSON,
2110		LINKS_01_JSON, 
2111		SCHEMA_01,
2112		HYPERSCHEMA_01,
2113		LINKS_01, 
2114		SCHEMA_02_JSON,
2115		HYPERSCHEMA_02_JSON,
2116		LINKS_02_JSON,
2117		SCHEMA_02,
2118		HYPERSCHEMA_02,
2119		LINKS_02, 
2120		SCHEMA_03_JSON,
2121		HYPERSCHEMA_03_JSON,
2122		LINKS_03_JSON,
2123		SCHEMA_03,
2124		HYPERSCHEMA_03,
2125		LINKS_03;
2126
2127	InitializationError = function InitializationError(instance, schema, attr, message, details) {
2128		Error.call(this, message);
2129
2130		this.uri = instance.getURI();
2131		this.schemaUri = schema.getURI();
2132		this.attribute = attr;
2133		this.message = message;
2134		this.description = message;  //IE
2135		this.details = details;
2136	}
2137	InitializationError.prototype = new Error();
2138	InitializationError.prototype.constructor = InitializationError;
2139	InitializationError.prototype.name = "InitializationError";
2140
2141	TYPE_VALIDATORS = {
2142		"string" : function (instance, report) {
2143			return instance.getType() === "string";
2144		},
2145
2146		"number" : function (instance, report) {
2147			return instance.getType() === "number";
2148		},
2149
2150		"integer" : function (instance, report) {
2151			return instance.getType() === "number" && instance.getValue() % 1 === 0;
2152		},
2153
2154		"boolean" : function (instance, report) {
2155			return instance.getType() === "boolean";
2156		},
2157
2158		"object" : function (instance, report) {
2159			return instance.getType() === "object";
2160		},
2161
2162		"array" : function (instance, report) {
2163			return instance.getType() === "array";
2164		},
2165
2166		"null" : function (instance, report) {
2167			return instance.getType() === "null";
2168		},
2169
2170		"any" : function (instance, report) {
2171			return true;
2172		}
2173	};
2174
2175	ENVIRONMENT = new JSV.Environment();
2176	ENVIRONMENT.setOption("strict", false);
2177	ENVIRONMENT.setOption("validateReferences", false);  //updated later
2178
2179	//
2180	// draft-00
2181	//
2182
2183	SCHEMA_00_JSON = {
2184		"$schema" : "http://json-schema.org/draft-00/hyper-schema#",
2185		"id" : "http://json-schema.org/draft-00/schema#",
2186		"type" : "object",
2187
2188		"properties" : {
2189			"type" : {
2190				"type" : ["string", "array"],
2191				"items" : {
2192					"type" : ["string", {"$ref" : "#"}]
2193				},
2194				"optional" : true,
2195				"uniqueItems" : true,
2196				"default" : "any",
2197
2198				"parser" : function (instance, self) {
2199					var parser;
2200
2201					if (instance.getType() === "string") {
2202						return instance.getValue();
2203					} else if (instance.getType() === "object") {
2204						return instance.getEnvironment().createSchema(
2205							instance, 
2206							self.getEnvironment().findSchema(self.resolveURI("#"))
2207						);
2208					} else if (instance.getType() === "array") {
2209						parser = self.getValueOfProperty("parser");
2210						return JSV.mapArray(instance.getProperties(), function (prop) {
2211							return parser(prop, self);
2212						});
2213					}
2214					//else
2215					return "any";
2216				},
2217
2218				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2219					var requiredTypes = JSV.toArray(schema.getAttribute("type")),
2220						x, xl, type, subreport, typeValidators;
2221
2222					//for instances that are required to be a certain type
2223					if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
2224						typeValidators = self.getValueOfProperty("typeValidators") || {};
2225
2226						//ensure that type matches for at least one of the required types
2227						for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
2228							type = requiredTypes[x];
2229							if (JSV.isJSONSchema(type)) {
2230								subreport = JSV.createObject(report);
2231								subreport.errors = [];
2232								subreport.validated = JSV.clone(report.validated);
2233								if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
2234									return true;
2234  //instance matches this schema
2235								}
2236							} else {
2237								if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
2238									if (typeValidators[type](instance, report)) {
2239										return true;  //type is valid
2240									}
2241								} else {
2242									return true;  //unknown types are assumed valid
2243								}
2244							}
2245						}
2246
2247						//if we get to this point, type is invalid
2248						report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
2249						return false;
2250					}
2251					//else, anything is allowed if no type is specified
2252					return true;
2253				},
2254
2255				"typeValidators" : TYPE_VALIDATORS
2256			},
2257
2258			"properties" : {
2259				"type" : "object",
2260				"additionalProperties" : {"$ref" : "#"},
2261				"optional" : true,
2262				"default" : {},
2263
2264				"parser" : function (instance, self, arg) {
2265					var env = instance.getEnvironment(),
2266						selfEnv = self.getEnvironment();
2267					if (instance.getType() === "object") {
2268						if (arg) {
2269							return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
2270						} else {
2271							return JSV.mapObject(instance.getProperties(), function (instance) {
2272								return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
2273							});
2274						}
2275					}
2276					//else
2277					return {};
2278				},
2279
2280				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2281					var propertySchemas, key;
2282					//this attribute is for object type instances only
2283					if (instance.getType() === "object") {
2284						//for each property defined in the schema
2285						propertySchemas = schema.getAttribute("properties");
2286						for (key in propertySchemas) {
2287							if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
2288								//ensure that instance property is valid
2289								propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
2290							}
2291						}
2292					}
2293				}
2294			},
2295
2296			"items" : {
2297				"type" : [{"$ref" : "#"}, "array"],
2298				"items" : {"$ref" : "#"},
2299				"optional" : true,
2300				"default" : {},
2301
2302				"parser" : function (instance, self) {
2303					if (instance.getType() === "object") {
2304						return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2305					} else if (instance.getType() === "array") {
2306						return JSV.mapArray(instance.getProperties(), function (instance) {
2307							return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2308						});
2309					}
2310					//else
2311					return instance.getEnvironment().createEmptySchema();
2312				},
2313
2314				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2315					var properties, items, x, xl, itemSchema, additionalProperties;
2316
2317					if (instance.getType() === "array") {
2318						properties = instance.getProperties();
2319						items = schema.getAttribute("items");
2320						additionalProperties = schema.getAttribute("additionalProperties");
2321
2322						if (JSV.typeOf(items) === "array") {
2323							for (x = 0, xl = properties.length; x < xl; ++x) {
2324								itemSchema = items[x] || additionalProperties;
2325								if (itemSchema !== false) {
2326									itemSchema.validate(properties[x], report, instance, schema, x);
2327								} else {
2328									report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
2329								}
2330							}
2331						} else {
2332							itemSchema = items || additionalProperties;
2333							for (x = 0, xl = properties.length; x < xl; ++x) {
2334								itemSchema.validate(properties[x], report, instance, schema, x);
2335							}
2336						}
2337					}
2338				}
2339			},
2340
2341			"optional" : {
2342				"type" : "boolean",
2343				"optional" : true,
2344				"default" : false,
2345
2346				"parser" : function (instance, self) {
2347					return !!instance.getValue();
2348				},
2349
2350				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2351					if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
2352						report.addError(instance, schema, "optional", "Property is required", false);
2353					}
2354				},
2355
2356				"validationRequired" : true
2357			},
2358
2359			"additionalProperties" : {
2360				"type" : [{"$ref" : "#"}, "boolean"],
2361				"optional" : true,
2362				"default" : {},
2363
2364				"parser" : function (instance, self) {
2365					if (instance.getType() === "object") {
2366						return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2367					} else if (instance.getType() === "boolean" && instance.getValue() === false) {
2368						return false;
2369					}
2370					//else
2371					return instance.getEnvironment().createEmptySchema();
2372				},
2373
2374				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2375					var additionalProperties, propertySchemas, properties, key;
2376					//we only need to check against object types as arrays do their own checking on this property
2377					if (instance.getType() === "object") {
2378						additionalProperties = schema.getAttribute("additionalProperties");
2379						propertySchemas = schema.getAttribute("properties") || {};
2380						properties = instance.getProperties();
2381						for (key in properties) {
2382							if (properties[key] !== O[key] && properties[key] && propertySchemas[key] === O[key]) {
2383								if (JSV.isJSONSchema(additionalProperties)) {
2384									additionalProperties.validate(properties[key], report, instance, schema, key);
2385								} else if (additionalProperties === false) {
2386									report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
2387								}
2388							}
2389						}
2390					}
2391				}
2392			},
2393
2394			"requires" : {
2395				"type" : ["string", {"$ref" : "#"}],
2396				"optional" : true,
2397
2398				"parser" : function (instance, self) {
2399					if (instance.getType() === "string") {
2400						return instance.getValue();
2401					} else if (instance.getType() === "object") {
2402						return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2403					}
2404				},
2405
2406				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2407					var requires;
2408					if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
2409						requires = schema.getAttribute("requires");
2410						if (typeof requires === "string") {
2411							if (parent.getProperty(requires).getType() === "undefined") {
2412								report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
2413							}
2414						} else if (JSV.isJSONSchema(requires)) {
2415							requires.validate(parent, report);  //WATCH: A "requires" schema does not support the "requires" attribute
2416						}
2417					}
2418				}
2419			},
2420
2421			"minimum" : {
2422				"type" : "number",
2423				"optional" : true,
2424
2425				"parser" : function (instance, self) {
2426					if (instance.getType() === "number") {
2427						return instance.getValue();
2428					}
2429				},
2430
2431				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2432					var minimum, minimumCanEqual;
2433					if (instance.getType() === "number") {
2434						minimum = schema.getAttribute("minimum");
2435						minimumCanEqual = schema.getAttribute("minimumCanEqual");
2436						if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
2437							report.addError(instance, schema, "minimum", "Number is less then the required minimum value", minimum);
2438						}
2439					}
2440				}
2441			},
2442
2443			"maximum" : {
2444				"type" : "number",
2445				"optional" : true,
2446
2447				"parser" : function (instance, self) {
2448					if (instance.getType() === "number") {
2449						return instance.getValue();
2450					}
2451				},
2452
2453				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2454					var maximum, maximumCanEqual;
2455					if (instance.getType() === "number") {
2456						maximum = schema.getAttribute("maximum");
2457						maximumCanEqual = schema.getAttribute("maximumCanEqual");
2458						if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
2459							report.addError(instance, schema, "maximum", "Number is greater then the required maximum value", maximum);
2460						}
2461					}
2462				}
2463			},
2464
2465			"minimumCanEqual" : {
2466				"type" : "boolean",
2467				"optional" : true,
2468				"requires" : "minimum",
2469				"default" : true,
2470
2471				"parser" : function (instance, self) {
2472					if (instance.getType() === "boolean") {
2473						return instance.getValue();
2474					}
2475					//else
2476					return true;
2477				}
2478			},
2479
2480			"maximumCanEqual" : {
2481				"type" : "boolean",
2482				"optional" : true,
2483				"requires" : "maximum",
2484				"default" : true,
2485
2486				"parser" : function (instance, self) {
2487					if (instance.getType() === "boolean") {
2488						return instance.getValue();
2489					}
2490					//else
2491					return true;
2492				}
2493			},
2494
2495			"minItems" : {
2496				"type" : "integer",
2497				"optional" : true,
2498				"minimum" : 0,
2499				"default" : 0,
2500
2501				"parser" : function (instance, self) {
2502					if (instance.getType() === "number") {
2503						return instance.getValue();
2504					}
2505					//else
2506					return 0;
2507				},
2508
2509				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2510					var minItems;
2511					if (instance.getType() === "array") {
2512						minItems = schema.getAttribute("minItems");
2513						if (typeof minItems === "number" && instance.getProperties().length < minItems) {
2514							report.addError(instance, schema, "minItems", "The number of items is less then the required minimum", minItems);
2515						}
2516					}
2517				}
2518			},
2519
2520			"maxItems" : {
2521				"type" : "integer",
2522				"optional" : true,
2523				"minimum" : 0,
2524
2525				"parser" : function (instance, self) {
2526					if (instance.getType() === "number") {
2527						return instance.getValue();
2528					}
2529				},
2530
2531				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2532					var maxItems;
2533					if (instance.getType() === "array") {
2534						maxItems = schema.getAttribute("maxItems");
2535						if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
2536							report.addError(instance, schema, "maxItems", "The number of items is greater then the required maximum", maxItems);
2537						}
2538					}
2539				}
2540			},
2541
2542			"pattern" : {
2543				"type" : "string",
2544				"optional" : true,
2545				"format" : "regex",
2546
2547				"parser" : function (instance, self) {
2548					if (instance.getType() === "string") {
2549						try {
2550							return new RegExp(instance.getValue());
2551						} catch (e) {
2552							return e;
2553						}
2554					}
2555				},
2556
2557				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2558					var pattern;
2559					try {
2560						pattern = schema.getAttribute("pattern");
2561						if (pattern instanceof Error) {
2562							report.addError(schema, self, "pattern", "Invalid pattern", schema.getValueOfProperty("pattern"));
2563						} else if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
2564							report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
2565						}
2566					} catch (e) {
2567						report.addError(schema, self, "pattern", "Invalid pattern", schema.getValueOfProperty("pattern"));
2568					}
2569				}
2570			},
2571
2572			"minLength" : {
2573				"type" : "integer",
2574				"optional" : true,
2575				"minimum" : 0,
2576				"default" : 0,
2577
2578				"parser" : function (instance, self) {
2579					if (instance.getType() === "number") {
2580						return instance.getValue();
2581					}
2582					//else
2583					return 0;
2584				},
2585
2586				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2587					var minLength;
2588					if (instance.getType() === "string") {
2589						minLength = schema.getAttribute("minLength");
2590						if (typeof minLength === "number" && instance.getValue().length < minLength) {
2591							report.addError(instance, schema, "minLength", "String is less then the required minimum length", minLength);
2592						}
2593					}
2594				}
2595			},
2596
2597			"maxLength" : {
2598				"type" : "integer",
2599				"optional" : true,
2600
2601				"parser" : function (instance, self) {
2602					if (instance.getType() === "number") {
2603						return instance.getValue();
2604					}
2605				},
2606
2607				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2608					var maxLength;
2609					if (instance.getType() === "string") {
2610						maxLength = schema.getAttribute("maxLength");
2611						if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
2612							report.addError(instance, schema, "maxLength", "String is greater then the required maximum length", maxLength);
2613						}
2614					}
2615				}
2616			},
2617
2618			"enum" : {
2619				"type" : "array",
2620				"optional" : true,
2621				"minItems" : 1,
2622				"uniqueItems" : true,
2623
2624				"parser" : function (instance, self) {
2625					if (instance.getType() === "array") {
2626						return instance.getValue();
2627					}
2628				},
2629
2630				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2631					var enums, x, xl;
2632					if (instance.getType() !== "undefined") {
2633						enums = schema.getAttribute("enum");
2634						if (enums) {
2635							for (x = 0, xl = enums.length; x < xl; ++x) {
2636								if (instance.equals(enums[x])) {
2637									return true;
2638								}
2639							}
2640							report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
2641						}
2642					}
2643				}
2644			},
2645
2646			"title" : {
2647				"type" : "string",
2648				"optional" : true
2649			},
2650
2651			"description" : {
2652				"type" : "string",
2653				"optional" : true
2654			},
2655
2656			"format" : {
2657				"type" : "string",
2658				"optional" : true,
2659
2660				"parser" : function (instance, self) {
2661					if (instance.getType() === "string") {
2662						return instance.getValue();
2663					}
2664				},
2665
2666				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2667					var format, formatValidators;
2668					if (instance.getType() === "string") {
2669						format = schema.getAttribute("format");
2670						formatValidators = self.getValueOfProperty("formatValidators");
2671						if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
2672							report.addError(instance, schema, "format", "String is not in the required format", format);
2673						}
2674					}
2675				},
2676
2677				// JOSHFIRE: added a couple of format validators for "uri" and "email"
2678				"formatValidators" : {
2679					"uri": function (instance, report) {
2680						// Regular expression from @diegoperini taken from:
2681						// http://mathiasbynens.be/demo/url-regex
2682						// ... and only slightly adjusted for use in JavaScript
2683						var reUri = /^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+\-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+\-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;
2684						return !!reUri.test(instance._value);
2685					},
2686					"email": function (instance, report) {
2687						// Regular expression taken from:
2688						// http://www.regular-expressions.info/email.html
2689						var reEmail = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
2690						return !!reEmail.test(instance._value);
2691					}
2692				}
2693				// JOSHFIRE: end of custom code
2694				// "formatValidators": {}
2695			},
2696
2697			"contentEncoding" : {
2698				"type" : "string",
2699				"optional" : true
2700			},
2701
2702			"default" : {
2703				"type" : "any",
2704				"optional" : true
2705			},
2706
2707			"maxDecimal" : {
2708				"type" : "integer",
2709				"optional" : true,
2710				"minimum" : 0,
2711
2712				"parser" : function (instance, self) {
2713					if (instance.getType() === "number") {
2714						return instance.getValue();
2715					}
2716				},
2717
2718				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2719					var maxDecimal, decimals;
2720					if (instance.getType() === "number") {
2721						maxDecimal = schema.getAttribute("maxDecimal");
2722						if (typeof maxDecimal === "number") {
2723							decimals = instance.getValue().toString(10).split('.')[1];
2724							if (decimals && decimals.length > maxDecimal) {
2725								report.addError(instance, schema, "maxDecimal", "The number of decimal places is greater then the allowed maximum", maxDecimal);
2726							}
2727						}
2728					}
2729				}
2730			},
2731
2732			"disallow" : {
2733				"type" : ["string", "array"],
2734				"items" : {"type" : "string"},
2735				"optional" : true,
2736				"uniqueItems" : true,
2737
2738				"parser" : function (instance, self) {
2739					if (instance.getType() === "string" || instance.getType() === "array") {
2740						return instance.getValue();
2741					}
2742				},
2743
2744				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2745					var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
2746						x, xl, key, typeValidators, subreport;
2747
2748					//for instances that are required to be a certain type
2749					if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
2750						typeValidators = self.getValueOfProperty("typeValidators") || {};
2751
2752						//ensure that type matches for at least one of the required types
2753						for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
2754							key = disallowedTypes[x];
2755							if (JSV.isJSONSchema(key)) {  //this is supported draft-03 and on
2756								subreport = JSV.createObject(report);
2757								subreport.errors = [];
2758								subreport.validated = JSV.clone(report.validated);
2759								if (key.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
2760									//instance matches this schema
2761									report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
2762									return false;  
2763								}
2764							} else if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
2765								if (typeValidators[key](instance, report)) {
2766									report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
2767									return false;
2768								}
2769							} 
2770							/*
2771							else {
2772								report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
2773								return false;
2774							}
2775							*/
2776						}
2777
2778						//if we get to this point, type is valid
2779						return true;
2780					}
2781					//else, everything is allowed if no disallowed types are specified
2782					return true;
2783				},
2784
2785				"typeValidators" : TYPE_VALIDATORS
2786			},
2787
2788			"extends" : {
2789				"type" : [{"$ref" : "#"}, "array"],
2790				"items" : {"$ref" : "#"},
2791				"optional" : true,
2792				"default" : {},
2793
2794				"parser" : function (instance, self) {
2795					if (instance.getType() === "object") {
2796						return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2797					} else if (instance.getType() === "array") {
2798						return JSV.mapArray(instance.getProperties(), function (instance) {
2799							return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
2800						});
2801					}
2802				},
2803
2804				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2805					var extensions = schema.getAttribute("extends"), x, xl;
2806					if (extensions) {
2807						if (JSV.isJSONSchema(extensions)) {
2808							extensions.validate(instance, report, parent, parentSchema, name);
2809						} else if (JSV.typeOf(extensions) === "array") {
2810							for (x = 0, xl = extensions.length; x < xl; ++x) {
2811								extensions[x].validate(instance, report, parent, parentSchema, name);
2812							}
2813						}
2814					}
2815				}
2816			}
2817		},
2818
2819		"optional" : true,
2820		"default" : {},
2821		"fragmentResolution" : "dot-delimited",
2822
2823		"parser" : function (instance, self) {
2824			if (instance.getType() === "object") {
2825				return instance.getEnvironment().createSchema(instance, self);
2826			}
2827		},
2828
2829		"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2830			var propNames = schema.getPropertyNames(), 
2831				x, xl,
2832				attributeSchemas = self.getAttribute("properties"),
2833				strict = instance.getEnvironment().getOption("strict"),
2834				validator;
2835
2836			for (x in attributeSchemas) {
2837				if (attributeSchemas[x] !== O[x]) {
2838					if (attributeSchemas[x].getValueOfProperty("validationRequired")) {
2839						JSV.pushUnique(propNames, x);
2840					}
2841					if (strict && attributeSchemas[x].getValueOfProperty("deprecated")) {
2842						JSV.popFirst(propNames, x);
2843					}
2844				}
2845			}
2846
2847			for (x = 0, xl = propNames.length; x < xl; ++x) {
2848				if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
2849					validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
2850					if (typeof validator === "function") {
2851						validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
2852					}
2853				}
2854			}
2855		}
2856	};
2857
2858	HYPERSCHEMA_00_JSON = {
2859		"$schema" : "http://json-schema.org/draft-00/hyper-schema#",
2860		"id" : "http://json-schema.org/draft-00/hyper-schema#",
2861
2862		"properties" : {
2863			"links" : {
2864				"type" : "array",
2865				"items" : {"$ref" : "links#"},
2866				"optional" : true,
2867
2868				"parser" : function (instance, self, arg) {
2869					var links,
2870						linkSchemaURI = self.getValueOfProperty("items")["$ref"],
2871						linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
2872						linkParser = linkSchema && linkSchema.getValueOfProperty("parser"),
2873						selfReferenceVariable;
2874					arg = JSV.toArray(arg);
2875
2876					if (typeof linkParser === "function") {
2877						links = JSV.mapArray(instance.getProperties(), function (link) {
2878							return linkParser(link, linkSchema);
2879						});
2880					} else {
2881						links = JSV.toArray(instance.getValue());
2882					}
2883
2884					if (arg[0]) {
2885						links = JSV.filterArray(links, function (link) {
2886							return link["rel"] === arg[0];
2887						});
2888					}
2889
2890					if (arg[1]) {
2891						selfReferenceVariable = self.getValueOfProperty("selfReferenceVariable");
2892						links = JSV.mapArray(links, function (link) {
2893							var instance = arg[1],
2894								href = link["href"];
2895							href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
2896								var value; 
2897								if (p1 === selfReferenceVariable) {
2898									value = instance.getValue();
2899								} else {
2900									value = instance.getValueOfProperty(p1);
2901								}
2902								return value !== undefined ? String(value) : "";
2903							});
2904							return href ? JSV.formatURI(instance.resolveURI(href)) : href;
2905						});
2906					}
2907
2908					return links;
2909				},
2910
2911				"selfReferenceVariable" : "-this"
2912			},
2913
2914			"fragmentResolution" : {
2915				"type" : "string",
2916				"optional" : true,
2917				"default" : "dot-delimited"
2918			},
2919
2920			"root" : {
2921				"type" : "boolean",
2922				"optional" : true,
2923				"default" : false
2924			},
2925
2926			"readonly" : {
2927				"type" : "boolean",
2928				"optional" : true,
2929				"default" : false
2930			},
2931
2932			"pathStart" : {
2933				"type" : "string",
2934				"optional" : true,
2935				"format" : "uri",
2936
2937				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
2938					var pathStart;
2939					if (instance.getType() !== "undefined") {
2940						pathStart = schema.getAttribute("pathStart");
2941						if (typeof pathStart === "string") {
2942							//TODO: Find out what pathStart is relative to
2943							if (instance.getURI().indexOf(pathStart) !== 0) {
2944								report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
2945							}
2946						}
2947					}
2948				}
2949			},
2950
2951			"mediaType" : {
2952				"type" : "string",
2953				"optional" : true,
2954				"format" : "media-type"
2955			},
2956
2957			"alternate" : {
2958				"type" : "array",
2959				"items" : {"$ref" : "#"},
2960				"optional" : true
2961			}
2962		},
2963
2964		"links" : [
2965			{
2966				"href" : "{$ref}",
2967				"rel" : "full"
2968			},
2969
2970			{
2971				"href" : "{$schema}",
2972				"rel" : "describedby"
2973			},
2974
2975			{
2976				"href" : "{id}",
2977				"rel" : "self"
2978			}
2979		],
2980
2981		"initializer" : function (instance) {
2982			var link, extension, extended;
2983
2984			//if there is a link to a different schema, update instance
2985			link = instance._schema.getLink("describedby", instance);
2986			if (link && instance._schema._uri !== link) {
2987				if (instance._env._schemas[link]) {
2988					instance._schema = instance._env._schemas[link];
2989					initializer = instance._schema.getValueOfProperty("initializer");
2990					if (typeof initializer === "function") {
2991						return initializer(instance);  //this function will finish initialization
2992					} else {
2993						return instance;  //no further initialization
2994					}
2995				} else if (instance._env._options["validateReferences"]) {
2996					throw new InitializationError(instance, instance._schema, "{link:describedby}", "Unknown schema reference", link);
2997				}
2998			}
2999
3000			//if there is a link to the full representation, replace instance
3001			link = instance._schema.getLink("full", instance);
3002			if (link && instance._uri !== link) {
3003				if (instance._env._schemas[link]) {
3004					instance = instance._env._schemas[link];
3005					return instance;  //retrieved schemas are guaranteed to be initialized
3006				} else if (instance._env._options["validateReferences"]) {
3007					throw new InitializationError(instance, instance._schema, "{link:full}", "Unknown schema reference", link);
3008				}
3009			}
3010
3011			//extend schema
3012			extension = instance.getAttribute("extends");
3013			if (JSV.isJSONSchema(extension)) {
3014				extended = JSV.inherits(extension, instance, true);
3015				instance = instance._env.createSchema(extended, instance._schema, instance._uri);
3016			}
3017
3018			//if instance has a URI link to itself, update it's own URI
3019			link = instance._schema.getLink("self", instance);
3020			if (JSV.typeOf(link) === "string") {
3021				instance._uri = JSV.formatURI(link);
3022			}
3023
3024			return instance;
3025		}
3026
3027		//not needed as JSV.inherits does the job for us
3028		//"extends" : {"$ref" : "http://json-schema.org/schema#"}
3029	};
3030
3031	LINKS_00_JSON = {
3032		"$schema" : "http://json-schema.org/draft-00/hyper-schema#",
3033		"id" : "http://json-schema.org/draft-00/links#",
3034		"type" : "object",
3035
3036		"properties" : {
3037			"href" : {
3038				"type" : "string"
3039			},
3040
3041			"rel" : {
3042				"type" : "string"
3043			},
3044
3045			"method" : {
3046				"type" : "string",
3047				"default" : "GET",
3048				"optional" : true
3049			},
3050
3051			"enctype" : {
3052				"type" : "string",
3053				"requires" : "method",
3054				"optional" : true
3055			},
3056
3057			"properties" : {
3058				"type" : "object",
3059				"additionalProperties" : {"$ref" : "hyper-schema#"},
3060				"optional" : true,
3061
3062				"parser" : function (instance, self, arg) {
3063					var env = instance.getEnvironment(),
3064						selfEnv = self.getEnvironment(),
3065						additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
3066					if (instance.getType() === "object") {
3067						if (arg) {
3068							return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
3069						} else {
3070							return JSV.mapObject(instance.getProperties(), function (instance) {
3071								return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
3072							});
3073						}
3074					}
3075				}
3076			}
3077		},
3078
3079		"parser" : function (instance, self) {
3080			var selfProperties = self.getProperty("properties");
3081			if (instance.getType() === "object") {
3082				return JSV.mapObject(instance.getProperties(), function (property, key) {
3083					var propertySchema = selfProperties.getProperty(key),
3084						parser = propertySchema && propertySchema.getValueOfProperty("parser");
3085					if (typeof parser === "function") {
3086						return parser(property, propertySchema);
3087					}
3088					//else
3089					return property.getValue();
3090				});
3091			}
3092			return instance.getValue();
3093		}
3094	};
3095
3096	ENVIRONMENT.setOption("defaultFragmentDelimiter", ".");
3097	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-00/schema#");  //updated later
3098
3099	SCHEMA_00 = ENVIRONMENT.createSchema(SCHEMA_00_JSON, true, "http://json-schema.org/draft-00/schema#");
3100	HYPERSCHEMA_00 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_00, ENVIRONMENT.createSchema(HYPERSCHEMA_00_JSON, true, "http://json-schema.org/draft-00/hyper-schema#"), true), true, "http://json-schema.org/draft-00/hyper-schema#");
3101
3102	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-00/hyper-schema#");
3103
3104	LINKS_00 = ENVIRONMENT.createSchema(LINKS_00_JSON, HYPERSCHEMA_00, "http://json-schema.org/draft-00/links#");
3105
3106	//We need to reinitialize these 3 schemas as they all reference each other
3107	SCHEMA_00 = ENVIRONMENT.createSchema(SCHEMA_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/schema#");
3108	HYPERSCHEMA_00 = ENVIRONMENT.createSchema(HYPERSCHEMA_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/hyper-schema#");
3109	LINKS_00 = ENVIRONMENT.createSchema(LINKS_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/links#");
3110
3111	//
3112	// draft-01
3113	//
3114
3115	SCHEMA_01_JSON = JSV.inherits(SCHEMA_00_JSON, {
3116		"$schema" : "http://json-schema.org/draft-01/hyper-schema#",
3117		"id" : "http://json-schema.org/draft-01/schema#"
3118	});
3119
3120	HYPERSCHEMA_01_JSON = JSV.inherits(HYPERSCHEMA_00_JSON, {
3121		"$schema" : "http://json-schema.org/draft-01/hyper-schema#",
3122		"id" : "http://json-schema.org/draft-01/hyper-schema#"
3123	});
3124
3125	LINKS_01_JSON = JSV.inherits(LINKS_00_JSON, {
3126		"$schema" : "http://json-schema.org/draft-01/hyper-schema#",
3127		"id" : "http://json-schema.org/draft-01/links#"
3128	});
3129
3130	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-01/schema#");  //update later
3131
3132	SCHEMA_01 = ENVIRONMENT.createSchema(SCHEMA_01_JSON, true, "http://json-schema.org/draft-01/schema#");
3133	HYPERSCHEMA_01 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_01, ENVIRONMENT.createSchema(HYPERSCHEMA_01_JSON, true, "http://json-schema.org/draft-01/hyper-schema#"), true), true, "http://json-schema.org/draft-01/hyper-schema#");
3134
3135	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-01/hyper-schema#");
3136
3137	LINKS_01 = ENVIRONMENT.createSchema(LINKS_01_JSON, HYPERSCHEMA_01, "http://json-schema.org/draft-01/links#");
3138
3139	//We need to reinitialize these 3 schemas as they all reference each other
3140	SCHEMA_01 = ENVIRONMENT.createSchema(SCHEMA_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/schema#");
3141	HYPERSCHEMA_01 = ENVIRONMENT.createSchema(HYPERSCHEMA_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/hyper-schema#");
3142	LINKS_01 = ENVIRONMENT.createSchema(LINKS_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/links#");
3143
3144	//
3145	// draft-02
3146	//
3147
3148	SCHEMA_02_JSON = JSV.inherits(SCHEMA_01_JSON, {
3149		"$schema" : "http://json-schema.org/draft-02/hyper-schema#",
3150		"id" : "http://json-schema.org/draft-02/schema#",
3151
3152		"properties" : {
3153			"uniqueItems" : {
3154				"type" : "boolean",
3155				"optional" : true,
3156				"default" : false,
3157
3158				"parser" : function (instance, self) {
3159					return !!instance.getValue();
3160				},
3161
3162				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3163					var value, x, xl, y, yl;
3164					if (instance.getType() === "array" && schema.getAttribute("uniqueItems")) {
3165						value = instance.getProperties();
3166						for (x = 0, xl = value.length - 1; x < xl; ++x) {
3167							for (y = x + 1, yl = value.length; y < yl; ++y) {
3168								if (value[x].equals(value[y])) {
3169									report.addError(instance, schema, "uniqueItems", "Array can only contain unique items", { x : x, y : y });
3170								}
3171							}
3172						}
3173					}
3174				}
3175			},
3176
3177			"maxDecimal" : {
3178				"deprecated" : true
3179			},
3180
3181			"divisibleBy" : {
3182				"type" : "number",
3183				"minimum" : 0,
3184				"minimumCanEqual" : false,
3185				"optional" : true,
3186
3187				"parser" : function (instance, self) {
3188					if (instance.getType() === "number") {
3189						return instance.getValue();
3190					}
3191				},
3192
3193				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3194					var divisor;
3195					if (instance.getType() === "number") {
3196						divisor = schema.getAttribute("divisibleBy");
3197						if (divisor === 0) {
3198							report.addError(instance, schema, "divisibleBy", "Nothing is divisible by 0", divisor);
3199						} else if (divisor !== 1 && ((instance.getValue() / divisor) % 1) !== 0) {
3200							report.addError(instance, schema, "divisibleBy", "Number is not divisible by " + divisor, divisor);
3201						}
3202					}
3203				}
3204			}
3205		},
3206
3207		"fragmentResolution" : "slash-delimited"
3208	});
3209
3210	HYPERSCHEMA_02_JSON = JSV.inherits(HYPERSCHEMA_01_JSON, {
3211		"id" : "http://json-schema.org/draft-02/hyper-schema#",
3212
3213		"properties" : {
3214			"fragmentResolution" : {
3215				"default" : "slash-delimited"
3216			}
3217		}
3218	});
3219
3220	LINKS_02_JSON = JSV.inherits(LINKS_01_JSON, {
3221		"$schema" : "http://json-schema.org/draft-02/hyper-schema#",
3222		"id" : "http://json-schema.org/draft-02/links#",
3223
3224		"properties" : {
3225			"targetSchema" : {
3226				"$ref" : "hyper-schema#",
3227
3228				//need this here because parsers are run before links are resolved
3229				"parser" : HYPERSCHEMA_01.getAttribute("parser")
3230			}
3231		}
3232	});
3233
3234	ENVIRONMENT.setOption("defaultFragmentDelimiter", "/");
3235	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-02/schema#");  //update later
3236
3237	SCHEMA_02 = ENVIRONMENT.createSchema(SCHEMA_02_JSON, true, "http://json-schema.org/draft-02/schema#");
3238	HYPERSCHEMA_02 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_02, ENVIRONMENT.createSchema(HYPERSCHEMA_02_JSON, true, "http://json-schema.org/draft-02/hyper-schema#"), true), true, "http://json-schema.org/draft-02/hyper-schema#");
3239
3240	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-02/hyper-schema#");
3241
3242	LINKS_02 = ENVIRONMENT.createSchema(LINKS_02_JSON, HYPERSCHEMA_02, "http://json-schema.org/draft-02/links#");
3243
3244	//We need to reinitialize these 3 schemas as they all reference each other
3245	SCHEMA_02 = ENVIRONMENT.createSchema(SCHEMA_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/schema#");
3246	HYPERSCHEMA_02 = ENVIRONMENT.createSchema(HYPERSCHEMA_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/hyper-schema#");
3247	LINKS_02 = ENVIRONMENT.createSchema(LINKS_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/links#");
3248
3249	//
3250	// draft-03
3251	//
3252
3253	function getMatchedPatternProperties(instance, schema, report, self) {
3254		var matchedProperties = {}, patternProperties, pattern, regexp, properties, key;
3255
3256		if (instance.getType() === "object") {
3257			patternProperties = schema.getAttribute("patternProperties");
3258			properties = instance.getProperties();
3259			for (pattern in patternProperties) {
3260				if (patternProperties[pattern] !== O[pattern]) {
3261					regexp = null;
3262					try {
3263						regexp = new RegExp(pattern);
3264					} catch (e) {
3265						if (report) {
3266							report.addError(schema, self, "patternProperties", "Invalid pattern", pattern);
3267						}
3268					}
3269
3270					if (regexp) {
3271						for (key in properties) {
3272							if (properties[key] !== O[key]  && regexp.test(key)) {
3273								matchedProperties[key] = matchedProperties[key] ? JSV.pushUnique(matchedProperties[key], patternProperties[pattern]) : [ patternProperties[pattern] ];
3274							}
3275						}
3276					}
3277				}
3278			}
3279		}
3280
3281		return matchedProperties;
3282	}
3283
3284	SCHEMA_03_JSON = JSV.inherits(SCHEMA_02_JSON, {
3285		"$schema" : "http://json-schema.org/draft-03/schema#",
3286		"id" : "http://json-schema.org/draft-03/schema#",
3287
3288		"properties" : {
3289			"patternProperties" : {
3290				"type" : "object",
3291				"additionalProperties" : {"$ref" : "#"},
3292				"default" : {},
3293
3294				"parser" : SCHEMA_02.getValueOfProperty("properties")["properties"]["parser"],
3295
3296				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3297					var matchedProperties, key, x;
3298					if (instance.getType() === "object") {
3299						matchedProperties = getMatchedPatternProperties(instance, schema, report, self);
3300						for (key in matchedProperties) {
3301							if (matchedProperties[key] !== O[key]) {
3302								x = matchedProperties[key].length;
3303								while (x--) {
3304									matchedProperties[key][x].validate(instance.getProperty(key), report, instance, schema, key);
3305								}
3306							}
3307						}
3308					}
3309				}
3310			},
3311
3312			"additionalProperties" : {
3313				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3314					var additionalProperties, propertySchemas, properties, matchedProperties, key;
3315					if (instance.getType() === "object") {
3316						additionalProperties = schema.getAttribute("additionalProperties");
3317						propertySchemas = schema.getAttribute("properties") || {};
3318						properties = instance.getProperties();
3319						matchedProperties = getMatchedPatternProperties(instance, schema);
3320						for (key in properties) {
3321							if (properties[key] !== O[key] && properties[key] && propertySchemas[key] === O[key] && matchedProperties[key] === O[key]) {
3322								if (JSV.isJSONSchema(additionalProperties)) {
3323									additionalProperties.validate(properties[key], report, instance, schema, key);
3324								} else if (additionalProperties === false) {
3325									report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
3326								}
3327							}
3328						}
3329					}
3330				}
3331			},
3332
3333			"items" : {
3334				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3335					var properties, items, x, xl, itemSchema, additionalItems;
3336
3337					if (instance.getType() === "array") {
3338						properties = instance.getProperties();
3339						items = schema.getAttribute("items");
3340						additionalItems = schema.getAttribute("additionalItems");
3341
3342						if (JSV.typeOf(items) === "array") {
3343							for (x = 0, xl = properties.length; x < xl; ++x) {
3344								itemSchema = items[x] || additionalItems;
3345								if (itemSchema !== false) {
3346									itemSchema.validate(properties[x], report, instance, schema, x);
3347								} else {
3348									report.addError(instance, schema, "additionalItems", "Additional items are not allowed", itemSchema);
3349								}
3350							}
3351						} else {
3352							itemSchema = items || additionalItems;
3353							for (x = 0, xl = properties.length; x < xl; ++x) {
3354								itemSchema.validate(properties[x], report, instance, schema, x);
3355							}
3356						}
3357					}
3358				}
3359			},
3360
3361			"additionalItems" : {
3362				"type" : [{"$ref" : "#"}, "boolean"],
3363				"default" : {},
3364
3365				"parser" : SCHEMA_02.getValueOfProperty("properties")["additionalProperties"]["parser"],
3366
3367				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3368					var additionalItems, properties, x, xl;
3369					//only validate if the "items" attribute is undefined
3370					if (instance.getType() === "array" && schema.getProperty("items").getType() === "undefined") {
3371						additionalItems = schema.getAttribute("additionalItems");
3372						properties = instance.getProperties();
3373
3374						if (additionalItems !== false) {
3375							for (x = 0, xl = properties.length; x < xl; ++x) {
3376								additionalItems.validate(properties[x], report, instance, schema, x);
3377							}
3378						} else if (properties.length) {
3379							report.addError(instance, schema, "additionalItems", "Additional items are not allowed", additionalItems);
3380						}
3381					}
3382				}
3383			},
3384
3385			"optional" : {
3386				"validationRequired" : false,
3387				"deprecated" : true
3388			},
3389
3390			"required" : {
3391				"type" : "boolean",
3392				"default" : false,
3393
3394				"parser" : function (instance, self) {
3395					return !!instance.getValue();
3396				},
3397
3398				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3399					if (instance.getType() === "undefined" && schema.getAttribute("required")) {
3400						report.addError(instance, schema, "required", "Property is required", true);
3401					}
3402				}
3403			},
3404
3405			"requires" : {
3406				"deprecated" : true
3407			},
3408
3409			"dependencies" : {
3410				"type" : "object",
3411				"additionalProperties" : {
3412					"type" : ["string", "array", {"$ref" : "#"}],
3413					"items" : {
3414						"type" : "string"
3415					}
3416				},
3417				"default" : {},
3418
3419				"parser" : function (instance, self, arg) {
3420					function parseProperty(property) {
3421						var type = property.getType();
3422						if (type === "string" || type === "array") {
3423							return property.getValue();
3424						} else if (type === "object") {
3425							return property.getEnvironment().createSchema(property, self.getEnvironment().findSchema(self.resolveURI("#")));
3426						}
3427					}
3428
3429					if (instance.getType() === "object") {
3430						if (arg) {
3431							return parseProperty(instance.getProperty(arg));
3432						} else {
3433							return JSV.mapObject(instance.getProperties(), parseProperty);
3434						}
3435					}
3436					//else
3437					return {};
3438				},
3439
3440				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3441					var dependencies, key, dependency, type, x, xl;
3442					if (instance.getType() === "object") {
3443						dependencies = schema.getAttribute("dependencies");
3444						for (key in dependencies) {
3445							if (dependencies[key] !== O[key] && instance.getProperty(key).getType() !== "undefined") {
3446								dependency = dependencies[key];
3447								type = JSV.typeOf(dependency);
3448								if (type === "string") {
3449									if (instance.getProperty(dependency).getType() === "undefined") {
3450										report.addError(instance, schema, "dependencies", 'Property "' + key + '" requires sibling property "' + dependency + '"', dependencies);
3451									}
3452								} else if (type === "array") {
3453									for (x = 0, xl = dependency.length; x < xl; ++x) {
3454										if (instance.getProperty(dependency[x]).getType() === "undefined") {
3455											report.addError(instance, schema, "dependencies", 'Property "' + key + '" requires sibling property "' + dependency[x] + '"', dependencies);
3456										}
3457									}
3458								} else if (JSV.isJSONSchema(dependency)) {
3459									dependency.validate(instance, report);
3460								}
3461							}
3462						}
3463					}
3464				}
3465			},
3466
3467			"minimumCanEqual" : {
3468				"deprecated" : true
3469			},
3470
3471			"maximumCanEqual" : {
3472				"deprecated" : true
3473			},
3474
3475			"exclusiveMinimum" : {
3476				"type" : "boolean",
3477				"default" : false,
3478
3479				"parser" : function (instance, self) {
3480					return !!instance.getValue();
3481				}
3482			},
3483
3484			"exclusiveMaximum" : {
3485				"type" : "boolean",
3486				"default" : false,
3487
3488				"parser" : function (instance, self) {
3489					return !!instance.getValue();
3490				}
3491			},
3492
3493			"minimum" : {
3494				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3495					var minimum, exclusiveMinimum;
3496					if (instance.getType() === "number") {
3497						minimum = schema.getAttribute("minimum");
3498						exclusiveMinimum = schema.getAttribute("exclusiveMinimum") || (!instance.getEnvironment().getOption("strict") && !schema.getAttribute("minimumCanEqual"));
3499						if (typeof minimum === "number" && (instance.getValue() < minimum || (exclusiveMinimum === true && instance.getValue() === minimum))) {
3500							report.addError(instance, schema, "minimum", "Number is less then the required minimum value", minimum);
3501						}
3502					}
3503				}
3504			},
3505
3506			"maximum" : {
3507				"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
3508					var maximum, exclusiveMaximum;
3509					if (instance.getType() === "number") {
3510						maximum = schema.getAttribute("maximum");
3511						exclusiveMaximum = schema.getAttribute("exclusiveMaximum") || (!instance.getEnvironment().getOption("strict") && !schema.getAttribute("maximumCanEqual"));
3512						if (typeof maximum === "number" && (instance.getValue() > maximum || (exclusiveMaximum === true && instance.getValue() === maximum))) {
3513							report.addError(instance, schema, "maximum", "Number is greater then the required maximum value", maximum);
3514						}
3515					}
3516				}
3517			},
3518
3519			"contentEncoding" : {
3520				"deprecated" : true
3521			},
3522
3523			"divisibleBy" : {
3524				"exclusiveMinimum" : true
3525			},
3526
3527			"disallow" : {
3528				"items" : {
3529					"type" : ["string", {"$ref" : "#"}]
3530				},
3531
3532				"parser" : SCHEMA_02_JSON["properties"]["type"]["parser"]
3533			},
3534
3535			"id" : {
3536				"type" : "string",
3537				"format" : "uri"
3538			},
3539
3540			"$ref" : {
3541				"type" : "string",
3542				"format" : "uri"
3543			},
3544
3545			"$schema" : {
3546				"type" : "string",
3547				"format" : "uri"
3548			}
3549		},
3550
3551		"dependencies" : {
3552			"exclusiveMinimum" : "minimum",
3553			"exclusiveMaximum" : "maximum"
3554		},
3555
3556		"initializer" : function (instance) {
3557			var link, extension, extended,
3558				schemaLink = instance.getValueOfProperty("$schema"),
3559				refLink = instance.getValueOfProperty("$ref"),
3560				idLink = instance.getValueOfProperty("id");
3561
3562			//if there is a link to a different schema, update instance
3563			if (schemaLink) {
3564				link = instance.resolveURI(schemaLink);
3565				if (link && instance._schema._uri !== link) {
3566					if (instance._env._schemas[link]) {
3567						instance._schema = instance._env._schemas[link];
3568						initializer = instance._schema.getValueOfProperty("initializer");
3569						if (typeof initializer === "function") {
3570							return initializer(instance);  //this function will finish initialization
3571						} else {
3572							return instance;  //no further initialization
3573						}
3574					} else if (instance._env._options["validateReferences"]) {
3575						throw new InitializationError(instance, instance._schema, "$schema", "Unknown schema reference", link);
3576					}
3577				}
3578			}
3579
3580			//if there is a link to the full representation, replace instance
3581			if (refLink) {
3582				link = instance.resolveURI(refLink);
3583				if (link && instance._uri !== link) {
3584					if (instance._env._schemas[link]) {
3585						instance = instance._env._schemas[link];
3586						return instance;  //retrieved schemas are guaranteed to be initialized
3587					} else if (instance._env._options["validateReferences"]) {
3588						throw new InitializationError(instance, instance._schema, "$ref", "Unknown schema reference", link);
3589					}
3590				}
3591			}
3592
3593			//extend schema
3594			extension = instance.getAttribute("extends");
3595			if (JSV.isJSONSchema(extension)) {
3596				extended = JSV.inherits(extension, instance, true);
3597				instance = instance._env.createSchema(extended, instance._schema, instance._uri);
3598			}
3599
3600			//if instance has a URI link to itself, update it's own URI
3601			if (idLink) {
3602				link = instance.resolveURI(idLink);
3603				if (JSV.typeOf(link) === "string") {
3604					instance._uri = JSV.formatURI(link);
3605				}
3606			}
3607
3608			return instance;
3609		}
3610	});
3611
3612	HYPERSCHEMA_03_JSON = JSV.inherits(HYPERSCHEMA_02_JSON, {
3613		"$schema" : "http://json-schema.org/draft-03/hyper-schema#",
3614		"id" : "http://json-schema.org/draft-03/hyper-schema#",
3615
3616		"properties" : {
3617			"links" : {
3618				"selfReferenceVariable" : "@"
3619			},
3620
3621			"root" : {
3622				"deprecated" : true
3623			},
3624
3625			"contentEncoding" : {
3626				"deprecated" : false  //moved from core to hyper
3627			},
3628
3629			"alternate" : {
3630				"deprecated" : true
3631			}
3632		}
3633	});
3634
3635	LINKS_03_JSON = JSV.inherits(LINKS_02_JSON, {
3636		"$schema" : "http://json-schema.org/draft-03/hyper-schema#",
3637		"id" : "http://json-schema.org/draft-03/links#",
3638
3639		"properties" : {
3640			"href" : {
3641				"required" : true,
3642				"format" : "link-description-object-template"
3643			},
3644
3645			"rel" : {
3646				"required" : true
3647			},
3648
3649			"properties" : {
3650				"deprecated" : true
3651			},
3652
3653			"schema" : {"$ref" : "http://json-schema.org/draft-03/hyper-schema#"}
3654		}
3655	});
3656
3657	ENVIRONMENT.setOption("validateReferences", true);
3658	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-03/schema#");  //update later
3659
3660	//prevent reference errors
3661	ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/schema#");
3662	ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/hyper-schema#");
3663	ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/links#");
3664
3665	SCHEMA_03 = ENVIRONMENT.createSchema(SCHEMA_03_JSON, true, "http://json-schema.org/draft-03/schema#");
3666	HYPERSCHEMA_03 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_03, ENVIRONMENT.createSchema(HYPERSCHEMA_03_JSON, true, "http://json-schema.org/draft-03/hyper-schema#"), true), true, "http://json-schema.org/draft-03/hyper-schema#");
3667	LINKS_03 = ENVIRONMENT.createSchema(LINKS_03_JSON, true, "http://json-schema.org/draft-03/links#");
3668
3669	ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-03/hyper-schema#");
3670
3671	//We need to reinitialize these schemas as they reference each other
3672	HYPERSCHEMA_03 = ENVIRONMENT.createSchema(HYPERSCHEMA_03.getValue(), HYPERSCHEMA_03, "http://json-schema.org/draft-03/hyper-schema#");
3673
3674	ENVIRONMENT.setOption("latestJSONSchemaSchemaURI", "http://json-schema.org/draft-03/schema#");
3675	ENVIRONMENT.setOption("latestJSONSchemaHyperSchemaURI", "http://json-schema.org/draft-03/hyper-schema#");
3676	ENVIRONMENT.setOption("latestJSONSchemaLinksURI", "http://json-schema.org/draft-03/links#");
3677
3678	//
3679	//Latest JSON Schema
3680	//
3681
3682	//Hack, but WAY faster then instantiating a new schema
3683	ENVIRONMENT._schemas["http://json-schema.org/schema#"] = SCHEMA_03;
3684	ENVIRONMENT._schemas["http://json-schema.org/hyper-schema#"] = HYPERSCHEMA_03;
3685	ENVIRONMENT._schemas["http://json-schema.org/links#"] = LINKS_03;
3686
3687	//
3688	//register environment
3689	//
3690
3691	JSV.registerEnvironment("json-schema-draft-03", ENVIRONMENT);
3692	if (!JSV.getDefaultEnvironmentID() || JSV.getDefaultEnvironmentID() === "
3692json-schema-draft-01" || JSV.getDefaultEnvironmentID() === "json-schema-draft-02") {
3693		JSV.setDefaultEnvironmentID("json-schema-draft-03");
3694	}
3695
3696}());
3697
3698
3699global.JSONFormValidator = exports.JSV;
3700})(this, false);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.