Node

Represents a single node of data, an immutable type like an int or a
string

@name Node
@extends BasicNode
@param Object details
@return Node
190709
function Node(details) {

		// If we got a string
		if(is.string(details)) {
			details = {"__type__": details};
		}

		// If the details are not an Object
		if(!is.object(details)) {
			throw 'details must be an Object';
		}

		// If the type is not found
		if(!('__type__' in details)) {
			throw 'missing "__type__" in details';
		}

		// If the type is not valid
		if(_validNode.indexOf(details['__type__']) == -1) {
			throw 'invalid "__type__" in details';
		}

		// Store the type and remove it from the details
		this._type	= details['__type__'];
		delete details['__type__'];

		// Init the value types
		this._regex = null;
		this._options = null;
		this._minimum = null;
		this._maximum = null;

		/**
		 * Compare IPs
		 *
		 * Compares two IPs and returns a status based on which is greater
		 * If first is less than second: -1
		 * If first is equal to second: 0
		 * If first is greater than second: 1
		 *
		 * @name compareIPs
		 * @access private
		 * @param String first			A string representing an IP address
		 * @param String second			A string representing an IP address
		 * @return int					-1, 0, 1
		 */
		var compareIPs = function compareIPs(first, second) {

			// If the two IPs are the same, return 0
			if(first == second) {
				return 0;
			}

			// Create lists from the split of each IP, store them as ints
			var aFirst = first.split('.');
			for(var i in aFirst) { aFirst[i] = parseInt(aFirst[i]); }
			var aSecond = second.split('.');
			for(var i in aSecond) { aSecond[i] = parseInt(aSecond[i]); }

			// Go through each part from left to right until we find the
			// 	difference
			for(var i = 0; i < 4; ++i) {

				// If the part of x is greater than the part of y
				if(aFirst[i] > aSecond[i]) {
					return 1;
				}

				// Else if the part of x is less than the part of y
				else if(aFirst[i] < aSecond[i]) {
					return -1;
				}
			}
		}

		/**
		 * Clean
		 *
		 * Cleans and returns the new value
		 *
		 * @name clean
		 * @access protected
		 * @param mixed value			The value to validate
		 * @return mixed
		 */
		this.clean = function clean(value) {

			// If the value is null and it's optional, return as is
			if(value == null && this._optional) {
				return null;
			}

			// If it's an ANY, there is no reasonable expectation that we know
			//	what the value should be, so we return it as is
			if(this._type == 'any') {
				//pass
			}

			// Else if it's a basic string type
			else if(['base64', 'ip', 'string', 'uuid'].indexOf(this._type) != -1) {

				// And not already a string
				if(!is.string(value)) {
					value = String(value);
				}
			}

			// Else if it's a BOOL just check if the value flags as positive
			else if(this._type == 'bool') {

				// If it's specifically a string, it needs to match a specific
				//	pattern to be true
				if(is.string(value)) {
					value = (['true', 'True', 'TRUE', 't', 'T', 'yes', 'Yes', 'YES', 'y', 'Y', 'x', '1'].indexOf(value) == -1) ? false : true;
				}
				else {
					value = value ? true : false;
				}
			}

			// Else if it's a date type
			else if(this._type == 'date') {

				// If it's a JavaScript type, convert it to a string
				if(value instanceof Date) {
					value = DateToStr(value);
				}

				// Else if it's already a string
				else if(is.string(value)) {
					//pass
				}

				// Else convert it to a string
				else {
					value = String(value);
				}
			}

			// Else if it's a datetime type
			else if(this._type == 'datetime') {

				// If it's a JavaScript type, convert it to a string
				if(value instanceof Date) {
					value = DateTimeToStr(value);
				}

				// Else if it's already a string
				else if(is.string(value)) {
					//pass
				}

				// Else convert it to a string
				else {
					value = String(value);
				}
			}

			// Else if it's a decimal
			else if(this._type == 'decimal') {

				// And not already a string
				if(!is.string(value)) {
					value = String(value);
				}
			}

			// Else if it's a float
			else if(this._type == 'float') {
				value = parseFloat(value);
			}

			// Else if it's an int type
			else if(['int', 'timestamp', 'uint'].indexOf(this._type) != -1) {

				// If it's a string
				if(is.string(value)) {

					// If it starts with 0
					if(value.charAt(0) == '0' && value.length > 1) {

						// If it's followed by X or x, it's hex
						if(['x', 'X'].indexOf(value.charAt(1)) != -1 && value.length > 2) {
							value = parseInt(value, 16)
						}

						// Else it's octal
						else {
							value = parseInt(value, 8)
						}
					}

					// Else it's base 10
					else {
						value = parseInt(value, 10);
					}
				}

				// Else if it's not an int already
				else if(!is.integer(value)) {
					value = parseInt(value);
				}
			}

			// Else if it's a JSON type
			else if(this._type == 'json') {

				// If it's already a string
				if(is.string(value)) {
					//pass
				}

				// Else, encode it
				else {
					value = JSON.stringify(value);
				}
			}

			// Else if it's an md5 type
			else if(this._type == 'md5') {

				// If it's a string
				if(is.string(value)) {
					//pass
				}

				// Else, try to convert it to a string
				else {
					value = String(value);
				}
			}

			// Else if it's a price type
			else if(this._type == 'price') {
				value = new Number(value).toFixed(2);
			}

			// Else if it's a time type
			else if(this._type == 'time') {

				// If it's a JavaScript type, get the time part
				if(value instanceof Date) {
					value = value.toTimeString().substr(0,8);
				}

				// Else if it's already a string
				else if(is.string(value)) {
					//pass
				}

				// Else convert it to a string
				else {
					value = String(value);
				}
			}

			// Else we probably forgot to add a new type
			else {
				throw '"' + this._type + '" has not been added to .clean()';
			}

			// Return the cleaned value
			return value;
		};

		/**
		 * Min/Max
		 *
		 * Sets or gets the minimum and/or maximum values for the Node. For
		 * getting, returns {"minimum":mixed,"maximum":mixed}
		 *
		 * @name minmax
		 * @access public
		 * @param mixed minimum			The minimum value
		 * @param mixed maximum			The maximum value
		 * @return void|Object
		 */
		this.minmax = function minmax(minimum, maximum) {

			// If neither min or max is set, this is a getter
			if(typeof minimum === 'undefined' && typeof maximum === 'undefined') {
				return {"minimum":this._minimum,"maximum":this._maximum};
			}

			// If the minimum is set
			if(minimum !== null) {

				// If the current type is a date, datetime, ip, or time
				if(['base64', 'date', 'datetime', 'ip', 'time'].indexOf(this._type) != -1) {

					// Make sure the value is valid for the type
					if(!is.string(minimum) || !_typeToRegex[this._type].test(minimum)) {
						throw '"__minimum__" is not valid for the current type: "' + this._type + '"';
					}
				}

				// Else if the type is an int (unsigned, timestamp), or a string
				//	in which the minimum/maximum are lengths
				else if(['int', 'string', 'timestamp', 'uint'].indexOf(this._type) != -1) {

					// If the value is not a valid int or long
					if(!is.integer(minimum)) {

						// If it's a valid representation of an integer
						if(is.string(minimum) && _typeToRegex['int'].test(minimum)) {

							// Convert it
							minimum = parseInt(minimum, 0);
						}

						// Else, raise an error
						else {
							throw '"__minimum__" must be an integer';
						}

						// If the type is meant to be unsigned
						if(['base64', 'string', 'timestamp', 'uint'].indexOf(this._type) != -1) {

							// And it's below zero
							if(minimum < 0) {
								throw '"__minimum__" must be an unsigned integer';
							}
						}
					}
				}

				// Else if the type is a decimal
				else if(this._type == 'decimal') {

					// If it's a not valid representation of a decimal
					if(!is.string(minimum) || !_typeToRegex['decimal'].test(minimum)) {

						// Throw an error
						throw '"__minimum__" not a valid decimal';
					}
				}

				// Else if the type is float
				else if(this._type == 'float') {

					// If it's not a float
					if(!is.float(minimum)) {

						// If we can't convert it to a float
						f	= parseFloat(minimum);
						if(isNaN(f)) {
							throw '"__minimum__" not a valid float';
						}

						// Store the parsed value
						minimum	= f;
					}
				}

				// Else if the type is price
				else if(this._type == 'price') {

					// If it's a not valid representation of a price
					if(!is.string(minimum) || !_typeToRegex['price'].test(minimum)) {

						// Throw an error
						throw '"__minimum__" not a valid price';
					}

				}

				// Else we can't have a minimum
				else {
					throw 'can not set __minimum__ for "' + this._type + '"';
				}

				// Store the minimum
				this._minimum = minimum;
			}

			// If the maximum is set
			if(maximum !== null) {

				// If the current type is a date, datetime, ip, or time
				if(['base64', 'date', 'datetime', 'ip', 'time'].indexOf(this._type) != -1) {

					// Make sure the value is valid for the type
					if(!is.string(maximum) || !_typeToRegex[this._type].test(maximum)) {
						throw '"__maximum__" is not valid for the current type: "' + this._type + '"';
					}
				}

				// Else if the type is an int (unsigned, timestamp), or a string
				//	in which the minimum/maximum are lengths
				else if(['int', 'string', 'timestamp', 'uint'].indexOf(this._type) != -1) {

					// If the value is not a valid int or long
					if(!is.integer(maximum)) {

						// If it's a valid representation of an integer
						if(is.string(maximum) && _typeToRegex['int'].test(maximum)) {

							// Convert it
							maximum	= parseInt(maximum, 0);
						}

						// Else, raise an error
						else {
							throw '"__maximum__" must be an integer';
						}

						// If the type is meant to be unsigned
						if(['base64', 'string', 'timestamp', 'uint'].indexOf(this._type) != -1) {

							// And it's below zero
							if(maximum < 0) {
								throw '"__maximum__" must be an unsigned integer';
							}
						}
					}
				}

				// Else if the type is decimal
				else if(this._type == 'decimal') {

					// If it's a not valid representation of a decimal
					if(!is.string(maximum) || !_typeToRegex['decimal'].test(maximum)) {

						// Throw an error
						throw '"__maximum__" not a valid decimal';
					}
				}

				// Else if the type is float
				else if(this._type == 'float') {

					// If it's not a float
					if(!is.float(maximum)) {

						// If we can't convert it to a float
						f	= parseFloat(maximum);
						if(isNaN(f)) {
							throw '"__maximum__" not a valid float';
						}

						// Store the parsed value
						maximum = f;
					}
				}

				// Else if the type is price
				else if(this._type == 'price') {

					// If it's a not valid representation of a price
					if(!is.string(maximum) || !_typeToRegex['price'].test(maximum)) {

						// Throw an error
						throw '"__maximum__" not a valid price';
					}
				}

				// Else we can't have a minimum
				else {
					throw 'can not set __maximum__ for "' + this._type + '"';
				}

				// If we also have a minimum
				if(this._minimum != null) {

					// If the type is an IP
					if(this._type == 'ip') {

						// If the min is above the maximum, we have a problem
						if(compareIPs(this._minimum, maximum) == 1) {
							throw '"__maximum__" can not be below "__minimum__"';
						}
					}

					// Else any other data type
					else {

						// If the min is above the maximum, we have a problem
						if(this._minimum > maximum) {
							throw '"__maximum__" can not be below "__minimum__"';
						}
					}
				}

				// Store the maximum
				this._maximum = maximum;
			}
		};

		/**
		 * Options
		 *
		 * Sets or gets the list of acceptable values for the Node
		 *
		 * @name options
		 * @access protected
		 * @param array opts			An array of valid values for the node when setting
		 * @return void|Array
		 */
		this.options = function options(opts) {

			// If opts aren't set, this is a getter
			if(typeof opts == 'undefined') {
				return this._options;
			}

			// Else this is a setter
			else {

				// If the options are not an Array
				if(!is.array(opts)) {
					throw '"__options__" must be an array';
				}

				// If the type is not one that can have options
				if(['any', 'base64', 'date', 'datetime', 'decimal',
						'float', 'int', 'ip', 'md5', 'price', 'string',
						'time', 'timestamp', 'uint', 'uuid'].indexOf(this._type) == -1) {
					throw 'can not set __options__ for "' + this._type + '"';
				}

				// Init the array of options to be saved
				var aOpts = [];

				// Go through each item and make sure it's unique and valid
				for(var i = 0; i < opts.length; ++i) {

					// Convert the value based on the type
					// If the type is a string one that we can validate
					if(['base64', 'date', 'datetime', 'ip', 'md5', 'time'].indexOf(this._type) != -1) {

						// If the value is not a string or doesn't match its regex,
						//	throw an error
						if(!is.string(opts[i]) || !_typeToRegex[this._type].test(opts[i])) {
							throw '"__options__[' + i + ']" is not valid for "' + this._type + '"';
						}
					}

					//	Else if it's decimal
					else if(this._type == 'decimal') {

						// And it's not a valid decimal representation
						if(is.string(opts[i]) || !_typeToRegex['decimal'].test(opts[i])) {

							// Throw an error
							throw '"__options__[' + i + ']" not a valid decimal';
						}
					}

					// Else if it's a float
					else if(this._type == 'float') {

						// If it's not a float
						if(!is.float(opts[i])) {

							// If we can't convert it to a float
							f = parseFloat(opts[i]);
							if(isNaN(f)) {
								throw '"__options__[' + i + ']" not a valid float';
							}

							// Store the parsed value
							opts[i]	= f;
						}
					}

					// Else if it's an integer
					else if(['int', 'timestamp', 'uint'].indexOf(this._type) != -1) {

						// If we don't already have an int
						if(!is.integer(opts[i])) {

							// If it's a valid representation of an integer
							if(is.string(opts[i]) && _typeToRegex['int'].test(opts[i])) {

								// Convert it
								opts[i]	= parseInt(opts[i], 0);
							}

							// Else, raise an error
							else {
								throw '"__options__[' + i + ']" must be an integer';
							}
						}

						// If the type is unsigned and negative, raise an error
						if(['timestamp', 'uint'].indexOf(this._type) != -1 && opts[i] < 0) {
							throw '"__options__[' + i + ']" must be an unsigned integer';
						}
					}

					//	Else if it's a price
					else if(this._type == 'price') {

						// And it's not a valid price representation
						if(!is.string(opts[i]) || !_typeToRegex['price'].test(opts[i])) {

							// Throw an error
							throw '"__options__[' + i + ']" not a valid price';
						}
					}

					// Else if the type is a string
					else if(this._type == 'string') {

						// If the value is not a string
						if(!is.string(opts[i])) {

							// Convert it
							opts[i]	= String(opts[i]);
						}
					}

					// If it's already in the list, raise an error
					if(aOpts.indexOf(opts[i]) != -1) {
						throw '"__options__[' + i + '] is a duplicate'
					}

					// Store the option
					else {
						aOpts.push(opts[i]);
					}
				}

				// Store the list of options
				this._options = aOpts;
			}
		};

		/**
		 * Regex
		 *
		 * Sets or gets the regular expression used to validate the Node
		 *
		 * @name regex
		 * @access protected
		 * @param str|RegExp regex		A regular expression string or object
		 * @return void|RegExp
		 */
		this.regex = function regex(regex) {

			// If regex was not set, this is a getter
			if(typeof regex === 'undefined') {
				return this._regex;
			}

			// Else this is a setter
			else {

				// If the type is not a string
				if(['decimal', 'int', 'price', 'string', 'timestamp', 'uint'].indexOf(this._type) == -1) {
					throw 'can not set __regex__ for "' + this._type + '"';
				}

				// If it's not a valid regex
				if(!(regex instanceof RegExp)) {

					// And it's not a string
					if(!is.string(regex)) {
						throw '"__regex__" must be a valid string or RegExp';
					}

					// Turn the string into a RegExp
					regex = new RegExp(regex);
				}

				// Store the regex
				this._regex = regex;
			}
		};

		/**
		 * To Object
		 *
		 * Returns the Node as an Object in the same format as is used in
		 * constructing it
		 *
		 * @name toObject
		 * @return Object
		 */
		this.toObject = function toObject() {

			// Init the Object we will return
			var oRet = {
				"__type__": this._type
			}

			// If there is a regex associated, add it
			if(this._regex) {
				oRet['__regex__'] = String(this._regex);
			}

			// Else if there were options associated, add them
			else if(this._options) {
				oRet['__options__'] = this._options;
			}

			// Else check for min and max and add if either are found
			else {
				if(this._minimum) {
					oRet['__minimum__'] = this._minimum;
				}
				if(this._maximum) {
					oRet['__maximum__'] = this._maximum;
				}
			}

			// Get the parents Object and add it to the return
			var oBasic = BasicNode.prototype.toObject.call(this);
			for(var k in oBasic) {
				oRet[k] = oBasic[k];
			}

			// Return
			return oRet;
		}

		/**
		 * Type
		 *
		 * Returns the type of Node this is
		 *
		 * @name type
		 * @return String
		 */
		this.type = function type() {
			return 'Node.' + this._type;
		};

		/**
		 * Valid
		 *
		 * Checks if a value is valid based on the instance's values
		 *
		 * @name valid
		 * @param mixed value			The value to validate
		 * @param array level			Names of parents to this node
		 * @return bool
		 */
		this.valid = function valid(value, level) {

			// Reset validation failures
			this.validation_failures = [];

			// If the value is None and it's optional, we're good
			if(value == null && this._optional) {
				return true;
			}

			// If level is not passed
			if(typeof level == 'undefined') {
				level = [];
			}

			// If we are validating an ANY field, immediately return true
			if(this._type == 'any') {

				// If there's a list of options
				if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options']);
						return false;
					} else {
						return true;
					}
				}

				// Else, just return true
				return true;
			}

			// If we are validating a DATE, DATETIME, IP or TIME data point
			else if(['base64', 'date', 'datetime', 'ip', 'md5', 'time', 'uuid'].indexOf(this._type) != -1) {

				// If it's a date, datetime, or time type and the value is a
				//	JavaScript Date
				if(['date', 'datetime', 'time'].indexOf(this._type) != -1 &&
					value instanceof Date) {
					return true;
				}

				// If the value is not a string
				if(!is.string(value)) {
					this.validation_failures.push([level.join('.'), 'not a string'])
					return false;
				}

				// If there's no match
				if(!_typeToRegex[this._type].test(value)) {
					this.validation_failures.push([level.join('.'), 'failed regex (internal)'])
					return false;
				}

				// Else if there's a list of options
				else if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}
			}

			// Else if we are validating some sort of integer
			else if(['int', 'timestamp', 'uint'].indexOf(this._type) != -1) {

				// If the type is a bool, fail immediately
				if(typeof value == 'boolean') {
					this.validation_failures.push([level.join('.'), 'is a bool'])
					return false;
				}

				// If it's not an int
				if(!is.integer(value)) {

					// And it's a valid representation of an int
					if(is.string(value) && _typeToRegex['int'].test(value)) {

						// If it starts with 0
						if(value.charAt(0) == '0' && value.length > 1) {

							// If it's followed by X or x, it's hex
							if(['X', 'x'].indexOf(value.charAt(1)) != -1 && value.length > 2) {
								value = parseInt(value, 16);
							}

							// Else it's octal
							else {
								value = parseInt(value, 8);
							}
						}

						// Else it's base 10
						else {
							value = parseInt(value, 10);
						}
					}

					// Else, return false
					else {
						this.validation_failures.push([level.join('.'), 'not an integer'])
						return false;
					}
				}

				// If it's not signed
				if(['timestamp', 'uint'].indexOf(this._type) != -1) {

					// If the value is below 0
					if(value < 0) {
						this.validation_failures.push([level.join('.'), 'signed'])
						return false;
					}
				}

				// If there is a regex
				if(this._regex) {

					// And it doesn't match the regex
					if(!this._regex.test(String(value))) {
						this.validation_failures.push([level.join('.'), 'failed regex (custom)'])
						return false;
					}
				}

				// If there's a list of options
				if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}
			}

			// Else if we are validating a bool
			else if(this._type == 'bool') {

				// If it's already a bool
				if(typeof value == 'boolean') {
					return true;
				}

				// If it's an int or long at 0 or 1
				if(is.integer(value) && [0, 1].indexOf(value) != -1) {
					return true;
				}

				// Else if it's a string
				else if(is.string(value)) {

					// If it's t, T, 1, f, F, or 0
					if(['true', 'true', 'TRUE', 't', 'T', '1', 'false', 'false', 'FALSE', 'f', 'F', '0'].indexOf(value) != -1) {
						return true;
					} else {
						this.validation_failures.push([level.join('.'), 'not a valid string representation of a bool'])
						return false;
					}
				}

				// Else it's no valid type
				else {
					this.validation_failures.push([level.join('.'), 'not valid bool replacement'])
					return false;
				}
			}

			// Else if we are validating a decimal value
			else if(this._type == 'decimal') {

				// If the type is a bool, fail immediately
				if(typeof value == 'boolean') {
					this.validation_failures.push([level.join('.'), 'is a bool'])
					return false;
				}

				// If it's not a string or doesn't match the regex
				if(!is.string(value) || !_typeToRegex['decimal'].test(value)) {
					this.validation_failures.push([level.join('.'), 'failed regex (internal)'])
					return false;
				}

				// Else if there's a list of options
				else if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}
			}

			// Else if we are validating a floating point value
			else if(this._type == 'float') {

				// If the type is a bool, fail immediately
				if(typeof value == 'boolean') {
					this.validation_failures.push([level.join('.'), 'is a bool'])
					return false;
				}

				// If it's not a string or doesn't match the regex
				if(is.string(value) && !_typeToRegex['decimal'].test(value)) {
					this.validation_failures.push([level.join('.'), 'failed regex (internal)'])
					return false;
				}

				// If we fail to convert the value
				value = parseFloat(value);
				if(isNaN(value)) {
					this.validation_failures.push([level.join('.'), 'can not be converted to float'])
					return false;
				}

				// If there's a list of options
				if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}
			}

			// Else if we are validating a JSON string
			else if(this._type == 'json') {

				// If it's already a string
				if(is.string(value)) {

					// Try to decode it
					try {
						JSON.parse(value);
						return true;
					}
					catch(err) {
						this.validation_failures.push([level.join('.'), 'Can not be decoded from JSON'])
						return false;
					}
				}

				// Else
				else {

					// Try to encode it
					try {
						value = JSON.stringify(value);
						return true;
					}
					catch(err) {
						this.validation_failures.push([level.join('.'), 'Can not be encoded to JSON'])
						return false;
					}
				}
			}

			// Else if we are validating a price value
			else if(this._type == 'price') {

				// If the type is a bool, fail immediately
				if(typeof value == 'boolean') {
					this.validation_failures.push([level.join('.'), 'is a bool'])
					return false;
				}

				// If it's not a string
				if(!is.string(value)) {

					// If it's a number
					if(typeof value == 'number') {
						value = String(value);
					} else {
						return false;
					}
				}

				// If it doesn't match the regex
				if(!_typeToRegex['price'].test(value)) {
					this.validation_failures.push([level.join('.'), 'failed regex (internal)'])
					return false;
				}

				// If there's a regex
				if(this._regex) {

					// And it doesn't match
					if(!this._regex.test(value)) {
						this.validation_failures.push([level.join('.'), 'failed regex (custom)'])
						return false;
					}
				}

				// Else if there's a list of options
				else if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}
			}

			// Else if we are validating a string value
			else if(this._type == 'string') {

				// If the value is not some form of string
				if(!is.string(value)) {
					this.validation_failures.push([level.join('.'), 'is not a string'])
					return false;
				}

				// If we have a regex
				if(this._regex) {

					// If it doesn't match the regex
					if(!this._regex.test(value)) {
						this.validation_failures.push([level.join('.'), 'failed regex (custom)'])
						return false;
					}
				}

				// If there's a list of options
				else if(this._options) {

					// Returns based on the option's existance
					if(this._options.indexOf(value) == -1) {
						this.validation_failures.push([level.join('.'), 'not in options'])
						return false;
					} else {
						return true;
					}
				}

				// Else
				else {

					// If there's a minimum length and we don't reach it
					if(this._minimum && value.length < this._minimum) {
						this.validation_failures.push([level.join('.'), 'not long enough'])
						return false;
					}

					// If there's a maximum length and we surpass it
					if(this._maximum && value.length > this._maximum) {
						this.validation_failures.push([level.join('.'), 'too long'])
						return false;
					}
				}

				// Return ok
				return true;
			}

			// If there is a minimum value (for non bools and strings)
			if(this._minimum) {

				// If we are checking an IP
				if(this._type == 'ip') {

					// If the IP is less than the minimum
					if(compareIPs(value, this._minimum) == -1) {
						this.validation_failures.push([level.join('.'), 'did not meet minimum'])
						return false;
					}
				}

				// Else
				else {

					// If the value is less than the minimum
					if(value < this._minimum) {
						this.validation_failures.push([level.join('.'), 'did not meet minimum'])
						return false;
					}
				}
			}

			// If there is a maximum value (for non bools and strings)
			if(this._maximum) {

				// If we are checking an IP
				if(this._type == 'ip') {

					// If the IP is greater than the maximum
					if(compareIPs(value, this._maximum) == 1) {
						this.validation_failures.push([level.join('.'), 'exceeds maximum'])
						return false;
					}
				}

				// Else
				else {

					// If the value is greater than the maximum
					if(value > this._maximum) {
						this.validation_failures.push([level.join('.'), 'exceeds maximum'])
						return false;
					}
				}
			}

			// Value has no issues
			return true;
		};
		// END public methods
		// CONTINUE constructor

		// If there's a regex string available
		if('__regex__' in details) {
			this.regex(details['__regex__']);
			delete details['__regex__'];
		}

		// Else if there's a list of options
		else if('__options__' in details) {
			this.options(details['__options__']);
			delete details['__options__'];
		}

		// Else
		else {

			// If there's a min or max
			var bMin = '__minimum__' in details;
			var bMax = '__maximum__' in details;

			if(bMin || bMax) {
				this.minmax(
					(bMin ? details['__minimum__'] : null),
					(bMax ? details['__maximum__'] : null)
				);
			}

			if(bMin) {
				delete details['__minimum__'];
			}
			if(bMax) {
				delete details['__maximum__'];
			}
		}

		// Call the parent constructor
		BasicNode.call(this, details);
	}
715005
function getString() {
  const type = NodeType.StringType;
  const token = tokens[pos];
  const line = token.ln;
  const column = token.col;
  const content = token.value;

  pos++;

  return newNode(type, content, line, column);
}
156076
public Object getValue(VariableNode node) {
        try {
            return debugger.getObjectProperty(node.object, node.id);
        } catch (Exception exc) {
            return "undefined";
        }
    }
1352175
function() {
    var node = this.member()
      , id;
    while (this.accept('[')) {
      node = new nodes.BinOp('[]', node, this.expression());
      this.expect(']');
    }
    // TODO: TernaryOp :)
    if (this.accept('=')) {
      node.op += '=';
      node.val = this.list();
      // @block support
      if (node.val.isEmpty) this.assignAtblock(node.val);
    }
    return node;
  }
1028781
function XML2Object(node, mapping){  // require for refactoring
    var nodeType = node.nodeType;
    var attributes = node.attributes;
    var firstChild = node.firstChild;

    if (!firstChild)
    {
      var firstAttr = attributes && attributes[0];
      if (nodeType == ELEMENT_NODE)
      {
        if (!firstAttr)
          return '';

        // test for <node xsi:nil="true"/>
        if (attributes.length == 1 &&
            (firstAttr.baseName || firstAttr.localName) == XSI_NIL_LOCALPART &&
            firstAttr.namespaceURI == XSI_NAMESPACE)
          return null;
      }
      else
      {
        if (!firstAttr)
          return null;
      }
    }
    else
    {
      // single child node and not an element -> return child nodeValue
      if (firstChild.nodeType != ELEMENT_NODE && firstChild === node.lastChild)
        return firstChild.nodeValue;
      else
        if (firstChild !== node.lastChild && firstChild.nodeType == TEXT_NODE)
        {
          var isSeparatedTextNode = true;
          var result = '';
          var cursor = firstChild;
          do
          {
            if (cursor.nodeType !== TEXT_NODE)
            {
              isSeparatedTextNode = false;
              break;
            }
            result += cursor.nodeValue;
          }
          while (cursor = cursor.nextSibling);

          if (isSeparatedTextNode)
            return result;
        }
    }

    var result = {};
    var nodes = [];
    var childNodesCount = 0;
    var value;
    var cursor;
    var object;
    var name;
    var isElement;
    var map;

    if (cursor = firstChild)
    {
      do
      {
        childNodesCount = nodes.push(cursor);
      }
      while (cursor = cursor.nextSibling);
    }

    if (attributes)
      for (var i = 0, attr; attr = attributes[i]; i++)
        nodes.push(attr);

    if (!mapping)
      mapping = {};

    for (var i = 0, child; child = nodes[i]; i++)
    {
      name = child.nodeName;
      isElement = i < childNodesCount;
      map = mapping[name];

      // fetch value
      if (isElement)
      {
        value = XML2Object(child, mapping);
      }
      else
      {
        if (name == 'xmlns')
          continue;

        value = child.nodeValue;
      }

      // mapping keys
      while (map)
      {
        if (map.storeName)
          value[map.storeName] = name;

        if (map.rename)
        {
          name = map.rename;
          map = mapping[name];
        }
        else
        {
          if (map.format)
            value = map.format(value);

          if (!result[name] && map.forceArray)
            value = [value];

          break;
        }
      }

      // store result
      if (name in result)
      {
        if ((object = result[name]) && object.push)
          object.push(value);
        else
          result[name] = [object, value];
      }
      else
        result[name] = value;
    }

    return result;
  }
876368
@Override
	public Node wrap(Object obj)
	{
		// Check if the object is level3
		if (!(obj instanceof Level3Element)) throw new IllegalArgumentException(
			"An object other than a Level3Element is trying to be wrapped: " + obj);

		// Check if the object passes the filter
		if (!passesFilters((Level3Element) obj)) return null;

		// Wrap if traversible

		if (obj instanceof PhysicalEntity)
		{
			return new PhysicalEntityWrapper((PhysicalEntity) obj, this);
		}
		else if (obj instanceof Conversion)
		{
			return new ConversionWrapper((Conversion) obj, this);
		}
		else if (obj instanceof TemplateReaction)
		{
			return new TemplateReactionWrapper((TemplateReaction) obj, this);
		}
		else if (obj instanceof Control)
		{
			return new ControlWrapper((Control) obj, this);
		}
		else
		{
			if (log.isWarnEnabled())
			{
				log.warn("Invalid BioPAX object to wrap as node. Ignoring: " + obj);
			}
			return null;
		}
	}
701775
public static String simpleObjectName(Object object) {
        if (object == null) {
            return "<null>";
        }
        StringBuilder builder = new StringBuilder();
        builder.append(simpleClassName(object.getClass()))
            .append('#')
            .append(objectId(object));
        return builder.toString();
    }
302981
@Override
    public boolean isLeaf(Object nodeObj) {
        if (debugger == null) {
            return true;
        }
        VariableNode node = (VariableNode) nodeObj;
        return children(node).length == 0;
    }
497884
private static Stream<String> nodeToStringStream(final org.apache.jena.graph.Node object) {
        if (object.isURI()) {
            return of(object.getURI());
        } else if (object.isLiteral()) {
            return of(object.getLiteralValue().toString());
        } else {
            return empty();
        }
    }
808121
function basics(node) {
  for (let i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) {
    const nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node);
    if (nodeStatus.hasChanged()) {
      return nodeStatus;
    }
    else {
      node = nodeStatus.newNode;
    }
  }
  return Node.Status.noChange(node);
}
293670
public static int nodeHashCode(final Node node) {
        assert node != null;
        int hash = 1 + node.getNodeType();
        hash = (hash * 17) + Arrays.hashCode(getNodeAttributes(node));
        if (node.hasAttributes()) {
            NamedNodeMap nodeMap = node.getAttributes();
            for (int i = 0; i < nodeMap.getLength(); ++i) {
                hash = (31 * hash) + nodeHashCode(nodeMap.item(i));
            }
        }
        if (node.hasChildNodes()) {
            NodeList childNodes = node.getChildNodes();
            for (int i = 0; i < childNodes.getLength(); ++i) {
                hash = (hash * 47) + nodeHashCode(childNodes.item(i));
            }
        }
        return hash;
    }
1047470
private Node getNode(Object entity, ObjectGraph graph, NodeState initialNodeState)
    {
        if (entity == null)
        {
            return null;
        }
        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(pd.getKunderaMetadata(),
                entity.getClass());

        // entity metadata could be null.
        if (entityMetadata == null)
        {
            throw new IllegalArgumentException(
                    "Entity object is invalid, operation failed. Please check previous log message for details");
        }

        Object id = PropertyAccessorHelper.getId(entity, entityMetadata);
        // Generate and set Id if @GeneratedValue present.
        if (((Field) entityMetadata.getIdAttribute().getJavaMember()).isAnnotationPresent(GeneratedValue.class))
        {
            if (!isIdSet(id))
            {
                id = idGenerator.generateAndSetId(entity, entityMetadata, pd, pd.getKunderaMetadata());
            }
        }

        if (!validator.isValidEntityObject(entity, entityMetadata))
        {
            throw new IllegalArgumentException(
                    "Entity object is invalid, operation failed. Please check previous log message for details");
        }

        // id = PropertyAccessorHelper.getId(entity, entityMetadata);

        String nodeId = ObjectGraphUtils.getNodeId(id, entity.getClass());
        Node node = graph.getNode(nodeId);

        // If this node is already there in graph (may happen for bidirectional
        // relationship, do nothing and return null)
        if (node != null)
        {
            if (node.isGraphCompleted())
            {
                return node;
            }
            return null;
        }

        // Construct this Node first, if one not already there in Persistence
        // Cache
        Node nodeInPersistenceCache = persistenceCache.getMainCache().getNodeFromCache(nodeId, pd);

        // Make a deep copy of entity data

        if (nodeInPersistenceCache == null)
        {
            node = new Node(nodeId, entity, initialNodeState, persistenceCache, id, pd);
        }
        else
        {
            node = nodeInPersistenceCache;
            node.setPersistenceCache(persistenceCache);

            // Determine whether this node is dirty based on comparison between
            // Node data and entity data
            // If dirty, set the entity data into node and mark it as dirty
            if (!DeepEquals.deepEquals(node.getData(), entity))
            {
                node.setDirty(true);
            }
            else if (node.isProcessed())
            {
                node.setDirty(false);
            }

            node.setData(entity);

            // If node is NOT in managed state, its data needs to be
            // replaced with the one provided in entity object
        }

        // Put this node into object graph
        graph.addNode(nodeId, node);

        // Iterate over relations and construct children nodes
        for (Relation relation : entityMetadata.getRelations())
        {
            if (relation != null)
            {
                // Child Object set in this entity
                Object childObject = PropertyAccessorHelper.getObject(entity, relation.getProperty());

                if (childObject != null && !ProxyHelper.isProxy(childObject))
                {
                    EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(pd.getKunderaMetadata(),
                            PropertyAccessorHelper.getGenericClass(relation.getProperty()));

                    if (metadata != null && relation.isJoinedByPrimaryKey())
                    {
                        PropertyAccessorHelper.setId(childObject, metadata,
                                PropertyAccessorHelper.getId(entity, entityMetadata));
                    }
                    // This child object could be either an entity(1-1 or M-1)
                    // or a
                    // collection/ Map of entities(1-M or M-M)
                    if (Collection.class.isAssignableFrom(childObject.getClass()))
                    {
                        // For each entity in the collection, construct a child
                        // node and add to graph
                        Collection childrenObjects = (Collection) childObject;

                        if (childrenObjects != null && !ProxyHelper.isProxyCollection(childrenObjects))

                            for (Object childObj : childrenObjects)
                            {
                                if (childObj != null)
                                {
                                    addChildNodesToGraph(graph, node, relation, childObj,
                                            metadata != null ? getChildNodeState(metadata, childObj) : initialNodeState);
                                }
                            }
                    }
                    else if (Map.class.isAssignableFrom(childObject.getClass()))
                    {
                        Map childrenObjects = (Map) childObject;
                        if (childrenObjects != null && !ProxyHelper.isProxyCollection(childrenObjects))
                        {
                            for (Map.Entry entry : (Set<Map.Entry>) childrenObjects.entrySet())
                            {
                                addChildNodesToGraph(graph, node, relation, entry,
                                        metadata != null ? getChildNodeState(metadata, entry) : initialNodeState);
                            }
                        }
                    }
                    else
                    {
                        // Construct child node and add to graph
                        addChildNodesToGraph(graph, node, relation, childObject,
                                metadata != null ? getChildNodeState(metadata, childObject) : initialNodeState);
                    }
                }
            }
        }

        // Means compelte graph is build.
        node.setGraphCompleted(true);
        return node;
    }
507290
function nodeFromDataToString(data, conversionContext) {
  var node = util.createElement(conversionContext.document, 'p');
  node.textContent = data.toString();
  return node;
}
1334370
private Object newArray(Object obj, Element node) throws Exception {

		// Get the type
		Class<?> aClass = java.lang.Object.class;
		String type = getAttribute(node, "type");
		final String id = getAttribute(node, "id");
		if (type != null) {
			aClass = TypeUtil.fromName(type);
			if (aClass == null) {
				if ("String".equals(type)) {
					aClass = java.lang.String.class;
				} else if ("URL".equals(type)) {
					aClass = java.net.URL.class;
				} else if ("InetAddress".equals(type)) {
					aClass = java.net.InetAddress.class;
				} else {
					aClass = Loader.loadClass(DOMJettyWebXmlParser.class, type,
							true);
				}
			}
		}

		List<Object> al = null;

		Element[] children = getChildren(node, "Item");
		for (Element item : children) {
			String nid = getAttribute(item, "id");
			Object v = value(obj, item);

			if (al == null) {
				al = new ArrayList<>();
			}

			al.add((v == null && aClass.isPrimitive()) ? ZERO : v);
			if (nid != null) {
				_idMap.put(nid, v);
			}
		}

		Object array = toArray(al, aClass);
		if (id != null) {
			_idMap.put(id, array);
		}
		return array;
	}
288872
private Object newMap(Object obj, Element node) throws Exception {
		String id = getAttribute(node, "id");

		Map<Object, Object> map = new HashMap<>();
		if (id != null) {
			_idMap.put(id, map);
		}

		Element[] children = getChildren(node);
		for (int i = 0; i < children.length; i++) {

			Element element = children[i];

			if (!element.getTagName().equals("Entry")) {
				throw new IllegalStateException("Not an Entry");
			}

			Element key = null;
			Element value = null;

			Element[] entries = getChildren(element);
			for (int j = 0; j < entries.length; j++) {
				Element item = entries[j];
				if (!item.getTagName().equals("Item")) {
					throw new IllegalStateException("Not an Item");
				}
				if (key == null) {
					key = item;
				} else {
					value = item;
				}
			}

			if (key == null || value == null) {
				throw new IllegalStateException("Missing Item in Entry");
			}
			String kid = getAttribute(key, "id");
			String vid = getAttribute(value, "id");

			Object k = value(obj, key);
			Object v = value(obj, value);
			map.put(k, v);

			if (kid != null) {
				_idMap.put(kid, k);
			}
			if (vid != null) {
				_idMap.put(vid, v);
			}
		}

		return map;
	}
280524
public AstNode node( String name ) {
        CheckArg.isNotNull(name, "name");
        AstNode node = new AstNode(name);
        node.setProperty(JCR_PRIMARY_TYPE, NT_UNSTRUCTURED);
        return node;
    }
1160940
SimpleNode getNode() {
        if (this.callerInfoNode != null)
            return this.callerInfoNode;
        if (this.parent != null)
            return this.parent.getNode();
        else
            return null;
    }