Example #1
0
/**
 * Detect whether the value has CommonJS Promise/A+ interface or not
 * @private
 */
function isPromiseLike(v) {
  return _.isObject(v) && _.isFunction(v.then);
}
Example #2
0
 var parseError = options.parseError || function(errs) {
   var err = _.isArray(errs) ? errs[0] : errs;
   if (_.isObject(err) && _.isString(err.message)) { return err; }
 };
exports.docPredicate = function (result, condition, value, conditions) {
  //if we have an array of objects, this is a deep traversal
  //we'll need to use a contains query to be sure we flex the index
  if(_.isArray(value) && _.isObject(value[0])) {
    //stringify the passed-in params
    result.params.push(JSON.stringify(conditions));
    result.predicates.push(util.format("body @> $%s", result.params.length + result.offset));
  }

  //if we have equality here, just use a JSON contains
  else if (condition.operator === '=' && !_.isArray(value)) {
    //parse the value into stringy JSON
    var param = {};
    param[condition.field]=value;
    result.params.push(JSON.stringify(param));
    result.predicates.push(util.format("body @> $%s", result.params.length + result.offset));
    return result;
  }

  //comparison stuff - same as method above but this time
  //we'll be coercing the document key values using pg's ::
  //not ideal, but it works nicely
  else if (_.isBoolean(value)) {
    result.predicates.push(
      util.format("(body ->> '%s')::boolean %s %s", condition.field, condition.operator, value)
    );
  } else if(_.isDate(value)) {
    result.params.push(value);
    result.predicates.push(
      util.format("(body ->> '%s')::timestamp %s $%d",
        condition.field,
        condition.operator,
        result.params.length + result.offset)
    );
  } else if(_.isNumber(value)) {
    result.predicates.push(
      util.format("(body ->> '%s')::decimal %s %d", condition.field, condition.operator, value)
    );
  }

  //anything non-array handling
  else if (!_.isArray(value)) {
    result.params.push(value);
    result.predicates.push(
      util.format("(body ->> '%s') %s $%s",
        condition.field,
        condition.operator,
        result.params.length + result.offset)
    );
  } else {
    var arrayConditions = [];

    _.each(value, function(v) {
      result.params.push(v);
      arrayConditions.push("$" + (result.params.length + result.offset));
    });

    condition.operator = condition.operator === '=' ? 'IN' : 'NOT IN';

    result.predicates.push(
      util.format("(body ->> '%s') %s (%s)",
        condition.field,
        condition.operator,
        arrayConditions.join(', '))
    );
  }

  return result;
};
Example #4
0
		mapFileNameToDataset[relationName].forEach(function(datum) {
			datum.input = featureExtractor(datum.input, {});
			if (!_.isObject(datum.input))
				throw new Error("Expected feature vector to be a hash, but found "+JSON.stringify(datum.input));
			featureLookupTable.addFeatures(datum.input);
		});
Example #5
0
console.log(_.defaults({a:'a', b:'b'}, {a:'aa', c:'c'}));//{ a: 'a', b: 'b', c: 'c' }

// pick, omit返回一个对象的副本, 保留指定的属性或去掉指定的属性
console.log(_.pick({name:'tom', age:4}, 'name'));//{ name: 'tom' }
console.log(_.omit({name:'tom', age:4}, 'name'));//{ age: 4 }
// has 判断对象是否包含指定的属性名
console.log(_.has({a:1, b:2, c:3}, 'b')); //true
// isEqual: 判断两个对象是值相等
var moe = {name:'moe', b:[1,2,3]};
var clone = {name:'moe', b:[1,2,3]};
console.log(moe==clone);//false
console.log(_.isEqual(moe, clone));//true
//判断对象类型以下都为空
console.log(_.isEmpty({})); //如果object里没包含任何东西,将返回true
console.log(_.isArray([1,2,3]));
console.log(_.isObject({}));
console.log((function(){ return _.isArguments(arguments); })(1, 2, 3));
console.log(_.isFunction(console.log));
console.log(_.isString("moe"));
console.log(_.isNumber(8.4 * 5));
console.log(_.isFinite(-101));
console.log(_.isBoolean(true));
console.log(_.isDate(new Date()));
console.log(_.isNaN(NaN));
console.log(_.isNull(null));
console.log(_.isUndefined(undefined));

// invert _.invert(object)
// 返回一个object的副本,并且里面的键和值是对调的,要使之有效,必须确保object里所有的值都是唯一的且可以序列号成字符串
console.log(_.invert({a:'b', c:'d', e:'f'})); // { b: 'a', d: 'c', f: 'e' }
Example #6
0
 _.each(params, function(value, index) {
   if(_.isArray(value) || _.isObject(value)) {
     params[index] = JSON.stringify(value);
   }
 });
Example #7
0
			work: function( api, key, cachedPart, bid ) {

				winston.info('manager:startRequest: ' + key);

				var self = this;

				if (_.has( api, 'timeout') && _.isObject(cachedPart)) {
					self.timeout = setTimeout(function(self) {
						if(_.isObject(cachedPart)) {
							cachedPart.timeout = true;
							cachedPart.fromcache = true;
						} else {
							cachedPart= {
								"cname": key,
								"timeout" : true,
								"fromcache" : false
							};
						}
						manager.enqueue('finishRequest', cachedPart );
						self.finished = true;
					}, api.timeout, self)
				}

				api.resource( api.params, api.credentials, function( err, res ) {
		  			clearTimeout(self.timeout)
		  			delete self.timeout;

		  			if ( err ) {

		  				api.expires = ( now );
			  			tout = _.isUndefined(cachedPart) ? {} : cachedPart;
			  			tout.cname = key;
			  			tout.expires = api.expires;
			  			tout.fromcache = true;
			  			tout.err = err;
			  			winston.error('Problem retrieving data for ' + bid + ' from ' + key + ': ' + JSON.stringify(err));

		  			} else {

			  			winston.event('Get data for ' + bid + ' from ' + key + ', ' + res.size);

			  			// Perform cleanup function on API response
			  			if (_.has(api, 'cleanup')) {
				  			res = api.cleanup(res);
			  			}

			  			// Filter the response
			  			if (_.has(api, 'filter')) {
				  			filter ( res, api.filter );
			  			}

			  			// Build the stored response
			  			api.expires = ( new Date() ).addSeconds( api.cacheduration );
			  			bundle[key] = api;
			  			//client.set('bundle'+bid, JSON.stringify(bundle));
			  			var tout = {
			  				expires: api.expires,
			  				result: res,
			  				iid: api.iid,
			  				cname: key
			  			};

				   		// Save the API response to Redis
				   		client.set(bid+key, JSON.stringify(tout));
				   	}
					manager.enqueue('finishRequest', tout );
	  				self.finished = true;
			  	});
			}
Example #8
0
var normalizeProperties = function(properties, name) {
  // Allow for shorthand type declaration:

  // Check to see if the user passed in a raw type of a properties hash.
  if(properties) {
    // Raw type passed.
    // index: Type is translated to index: {type: Type}
    // Properties hash created.
    if(_.isUndefined(properties.type)) {
      properties = {type: properties};

    // Properties hash passed.
    // Copy properties hash before modifying.
    // Users can pass in their own custom types to the schema and we don't want to write to that object.
    // Especially since properties.name contains the index of our field and copying that will break functionality.
    } else {
      properties = _.extend({}, properties);
    }
  }

  // Type may be an object with properties.
  // If "type.type" exists, we'll assume it's meant to be properties.
  // This means that shorthand objects can't use the "type" index.
  // If "type" is necessary, they must be wrapped in a SchemaObject.
  if(_.isObject(properties.type) && !_.isUndefined(properties.type.type)) {
    _.each(properties.type, function(value, key) {
      if(_.isUndefined(properties[key])) {
        properties[key] = value;
      }
    });
    properties.type = properties.type.type;
  }

  // Null or undefined should be flexible and allow any value.
  if(properties.type === null || properties.type === undefined) {
    properties.type = 'any';

  // Convert object representation of type to lowercase string.
  // String is converted to 'string', Number to 'number', etc.
  } else if(properties.type.name) {
    properties.type = properties.type.name;
  }
  if(_.isString(properties.type)) {
    properties.type = properties.type.toLowerCase();
  }

  // index: [Type] or index: [] is translated to index: {type: Array, arrayType: Type}
  if(_.isArray(properties.type)) {
    if(_.size(properties.type)) {
      // Properties will be normalized when array is initialized.
      properties.arrayType = properties.type[0];
    }
    properties.type = 'array';
  }

  // index: {} or index: SchemaObject is translated to index: {type: Object, objectType: Type}
  // SchemaObject factory is initialized when raw schema is provided.
  if(!_.isString(properties.type)) {
    if(_.isFunction(properties.type)) {
      properties.objectType = properties.type;
      properties.type = 'object';
    } else if(_.isObject(properties.type)) {
      if(_.size(properties.type)) {
        properties.objectType = new SchemaObject(properties.type);
      }
      properties.type = 'object';
    }
  }

  // Set name if passed on properties.
  // It's used to show what field an error what generated on.
  if(name) {
    properties.name = name;
  }

  return properties;
};
Example #9
0
  return function(defaults) {
    var self = this,
        obj;

    // Public version of ourselves.
    // Overwritten with proxy if available.
    self._this = self;

    // Object used to store properties internally.
    self._obj = obj = {};

    // Schema as defined by constructor.
    self._schema = schema;

    // Errors, retrieved with getErrors().
    self._errors = [];

    // Options need to be accessible to onValueSet.
    self._options = options;

    // Normalize schema properties to allow for various shorthand declarations.
    _.each(schema, function(properties, index) {
      schema[index] = normalizeProperties.call(self, properties, index);
    });

    // Define getters/typecasts based off of schema.
    _.each(schema, function(properties, index) {
      // Use getter / typecast to intercept and re-route, transform, etc.
      defineGetter.call(self, index, properties);
      defineSetter.call(self, index, properties);
    });

    // Return object without getter/typecasts, extra properties, etc.
    this.toObject = function() {
      var getObj = {};

      // Populate all properties in schema.
      _.each(schema, function(properties, index) {
        // Do not write values to object that are marked as writeOnly.
        if(properties.invisible) {
          return;
        }

        // Fetch value from self[index] to route through the public interface.
        var value = self._this[index];

        // If value does not need to be cloned, place in index.
        if((value === undefined || value === null)
        || properties.type !== 'object' && properties.type !== 'array' && properties.type !== 'date') {
          getObj[index] = value;

        // Clone Object
        } else if(properties.type === 'object') {
          // Call toObject() method if defined (this allows us to return primitive objects instead of SchemaObjects).
          if(_.isFunction(value.toObject)) {
            getObj[index] = value.toObject();

          // If is non-SchemaType object, shallow clone so that properties modification don't have an affect on the original object.
          } else if(_.isObject(value)) {
            getObj[index] = _.clone(value);
          }

        // Clone Array
        } else if(properties.type === 'array') {
          // Built in method to clone array to native type
          getObj[index] = value.toArray();

        // Clone Date object.
        } else if(properties.type === 'date') {
          // https://github.com/documentcloud/underscore/pull/863
          // _.clone doesn't work on Date object.
          getObj[index] = new Date(value.getTime());
        }
      });

      // If options contains toObject, pass through before returning final object.
      if(_.isFunction(this._options.toObject)) {
        getObj = this._options.toObject.call(this, getObj);
      }

      return getObj;
    };

    // toJSON is an interface used by JSON.stringify.
    // Return the raw object if called.
    this.toJSON = this.toObject;

    // Clear all values.
    this.clear = function() {
      _.each(self._schema, function(properties, index) {
        clearField.call(self._this, index, properties);
      });
    };

    // Get all errors.
    this.getErrors = function() {
      return self._errors;
    };

    // Clear all errors
    this.clearErrors = function() {
      self._errors = [];
    }

    // Harmony proxy used as interface to object allows to intercept all access.
    // Without Proxy we must register individual getter/typecasts to put any logic in place.
    // With Proxy, we still use the individual getter/typecasts, but also catch values that aren't in the schema.
    if(typeof(Proxy) !== 'undefined') {
      self._this = Proxy(self, {
        get: function(target, name, receiver) {
          if(options.dotNotation && name.indexOf('.') !== -1) {
            // Dot notation is on and the field name contains a dot.
            var fields = name.split('.'),
                result = self._obj;
            for (var i = 0, n = fields.length; i < n && result !== undefined; i++) {
              var field = fields[i];

              // If last in path, return the value.
              if(i === (n - 1)) {
                return result[field];
              } else {
                // The sub-object doesn't exist or isn't an object - return undefined.
                if(_.isUndefined(result[field]) || !_.isObject(result[field])) {
                  return undefined;
                }

                // Move onto next field.
                result = result[field];
              }
            }

            // For whatever reason, no value was found. Return undefined.
            return undefined;
          }

          // Using self routes to the registered getter without hitting the proxy and creating an infinite loop.
          return self[name];
        },
        set: function(target, name, value, receiver) {
          if(options.dotNotation && name.indexOf('.') !== -1) {
            // Dot notation is on and the field name contains a dot.
            var fields = name.split('.'),
                result = self._this;

            for (var i = 0, n = fields.length; i < n && result !== undefined; i++) {
              var field = fields[i];

              // If last in path, set value.
              if(i === (n - 1)) {
                result[field] = value;
              } else {
                // Create child object if it doesn't exist.
                if(_.isUndefined(result[field])) {
                  result[field] = {};
                }

                // If the field exists and isn't an object, abort.
                if(!_.isObject(result[field])) {
                  // TODO: We should throw a SetterError here, but this part of the typecast isn't wired to be able to throw errors.
                  return;
                }

                // Move onto next field.
                result = result[field];
              }
            }

            // Don't use typical handlers for any dot notation field.
            return;
          }

          if(!schema[name]) {
            if(options.strict) {
              // Strict mode means we don't want to deal with anything not in the schema.
              return;
            } else {
              // Add index to schema dynamically when value is set.
              // This is necessary for toObject to see the field.
              addToSchema.call(self, name, { type: 'any' });
            }
          }

          // This hits the registered setter but bypasses the proxy to avoid an infinite loop.
          self[name] = value;
        }
      });
    }

    // Populate runtime defaults as provided to this instance of object.
    // (Different than the default for each field - is simply a shortcut to populate values in object.)
    if(_.isObject(defaults)) {
      _.each(defaults, function(value, key) {
        self[key] = value;
      });
    };

    // If the proxy is available, we use that, otherwise fallback.
    return self._this;
  }
Example #10
0
 }, function(error, response, body) {
     if(_.isObject(body) && _.has(body, 'items') && body.items.length > 0) {
         callback(this.internalAPI.formatLink(body.items[0]));
     }
 }.bind(this));
Example #11
0
 }, function(error, response, body) {
     if(_.isObject(body) && _.has(body, 'items') && body.items.length > 0) {
         event.reply(this.internalAPI.formatLink(body.items[0]));
         dbot.modules.link.links[event.channel.name] = 'https://youtu.be/' + body.items[0].id;
     }
 }.bind(this));
Example #12
0
 }, function(error, response, body) {
     if(_.isObject(body) && _.has(body, 'items') && body.items.length > 0) {
         event.reply(this.internalAPI.formatPlaylistLink(body.items[0]));
     }
 }.bind(this));
Example #13
0
		partitions.partitions_hash(dataset, numOfFolds, function(train, test, fold) {
			var index = 1
			var stats

			while (index <= train.length)
	  		{
				
			  	var mytrainset = trainlen(train, index)

			  	index += (index < 10 ? 1 : 50)
				
				if (!_.isObject(mytrainset[0]))
					throw new Error("flatten is not correct")
				
				if (_.isArray(mytrainset[0]))
					throw new Error("flatten is not correct")
				
				if (!("input" in mytrainset[0]))
					throw new Error("flatten is not correct")

			  	_(len).times(function(n){

			  		var report = []

			  		n += 1

					mytrain = filtrain(mytrainset, n, 1)

					async.eachSeries(Object.keys(classifiers), function(classifier, callback1){ 
				  	// _.each(classifiers, function(classifier, name, list){ 
				  		console.log("start trainandTest")
				  		console.log(classifier)
		    			trainAndTest_async(classifiers[classifier], mytrain, test, function(err, stats){
				    		console.log("stop trainandTest")
			   	    		fs.appendFileSync(statusfile, classifier+"\n")
			   	    		fs.appendFileSync(statusfile, JSON.stringify(stats['stats'], null, 4))
			   	    		report.push(stats['stats'])
				    		callback1()
		    			})
			    		
				  	}, function(err){
						fiber.run(report)
					})

					var report1 = Fiber.yield()

			   	    extractGlobal(classifiers, mytrain.length/train[0].length, n,  report1, stat)

			   	    fs.appendFileSync(statusfile, JSON.stringify(stat, null, 4))

			   	    console.log("calc stats")
			   	    fs.appendFileSync(statusfile, setstat(mytrain))
			   	    console.log("stop stats")
			   	    
			   	    var cllist = Object.keys(classifiers)
			   	    var baseline = cllist[0]
			   	    var sotas = cllist.slice(1)

			   	    _.each(sotas, function(sota, key, list){ 
                    	_.each(stat, function(data, param, list){
							plot(fold, param, stat, baseline, sota)
							plot('average', param, stat, baseline, sota)
						})
			   	    }, this)
				})
			} //while (index < train.lelearning_curveslearning_curvesngth)
		})
Example #14
0
 _.clone = function(obj) {
   if (!_.isObject(obj)) return obj;
   return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
 };
Example #15
0
 }, function(error, response, body) {
     if(_.isObject(body) && _.has(body, 'entry')) {
         callback(this.internalAPI.formatLink(body.entry));
     }
 }.bind(this));
Example #16
0
var typecast = function(value, originalValue, properties) {
  // Allow transform to manipulate raw properties.
  if(properties.transform) {
    value = properties.transform.call(this, value, originalValue, properties);
  }

  switch(properties.type) {
    case 'string':
      // Reject if object or array.
      if(_.isObject(value) || _.isArray(value)) {
        throw new SetterError('String type cannot typecast Object or Array types.', value, originalValue, properties);
      }

      // If index is being set with null or undefined, set value and end.
      if(_.isUndefined(value) || value === null) {
        return value;
      }

      // Typecast to String.
      value = value + '';

      // If stringTransform function is defined, use.
      // This is used before we do validation checks (except to be sure we have a string at all).
      if(properties.stringTransform) {
        value = properties.stringTransform.call(this, value, originalValue, properties);
      }

      // If clip property & maxLength properties are set, the string should be clipped.
      // This is basically a shortcut property that could be done with stringTransform.
      if(properties.clip && !_.isUndefined(properties.maxLength)) {
        value = value.substr(0, properties.maxLength);
      }

      // If enum is being used, be sure the value is within definition.
      if(_.isArray(properties.enum) && properties.enum.indexOf(value) === -1) {
        throw new SetterError('String does not exist in enum list.', value, originalValue, properties);
      }

      // If minLength is defined, check to be sure the string is > minLength.
      if(!_.isUndefined(properties.minLength) && value.length < properties.minLength) {
        throw new SetterError('String length too short to meet minLength requirement.', value, originalValue, properties);
      }

      // If maxLength is defined, check to be sure the string is < maxLength.
      if(!_.isUndefined(properties.maxLength) && value.length > properties.maxLength) {
        throw new SetterError('String length too long to meet maxLength requirement.', value, originalValue, properties);
      }

      // If regex is defined, check to be sure the string matches the regex pattern.
      if(properties.regex && !properties.regex.test(value)) {
        throw new SetterError('String does not match regular expression pattern.', value, originalValue, properties);
      }

      return value;
      break;

    case 'number':
      // Set values for boolean.
      if(_.isBoolean(value)) {
        value = value ? 1 : 0;
      }

      // Reject if array, object, or not numeric.
      if( _.isArray(value) || _.isObject(value) || !isNumeric(value)) {
        throw new SetterError('Number type cannot typecast Array or Object types.', value, originalValue, properties);
      }

      // Typecast to number.
      value = value * 1;

      // Transformation after typecasting but before validation and filters.
      if(properties.numberTransform) {
        value = properties.numberTransform.call(this, value, originalValue, properties);
      }

      if(!_.isUndefined(properties.min) && value < properties.min) {
        throw new SetterError('Number is too small to meet min requirement.', value, originalValue, properties);
      }

      if(!_.isUndefined(properties.max) && value > properties.max) {
        throw new SetterError('Number is too big to meet max requirement.', value, originalValue, properties);
      }

      return value;
      break;

    case 'boolean':
      // If is String and is 'false', return false.
      if(value === 'false') {
        return false;
      }

      // If is Number, <0 is true and >0 is false.
      if(isNumeric(value)) {
        return (value * 1) > 0 ? true : false;
      }

      // Use Javascript to eval and return boolean.
      value = value ? true : false;

      // Transformation after typecasting but before validation and filters.
      if(properties.booleanTransform) {
        value = properties.booleanTransform.call(this, value, originalValue, properties);
      }

      return value;
      break;

    case 'array':
      // If it's an object, typecast to an array and return array.
      if(_.isObject(value)) {
        value = _.toArray(value);
      }

      // Reject if not array.
      if(!_.isArray(value)) {
        throw new SetterError('Array type cannot typecast non-Array types.', value, originalValue, properties);
      }

      // Arrays are never set directly.
      // Instead, the values are copied over to the existing SchemaArray instance.
      // The SchemaArray is initialized immediately and will always exist.
      originalValue.length = 0;
      _.each(value, function(arrayValue) {
        originalValue.push(arrayValue);
      });

      return originalValue;
      break;

    case 'object':
      // If it's not an Object, reject.
      if(!_.isObject(value)) {
        throw new SetterError('Object type cannot typecast non-Object types.', value, originalValue, properties);
      }

      // If object is schema object and an entirely new object was passed, clear values and set.
      // This preserves the object instance.
      if(properties.objectType) {
        // The object will usually exist because it's initialized immediately for deep access within SchemaObjects.
        // However, in the case of Array elements, it will not exist.
        var schemaObject;
        if(!_.isUndefined(originalValue)) {
          // Clear existing values.
          schemaObject = originalValue;
          schemaObject.clear();
        } else {
          // The SchemaObject doesn't exist yet. Let's initialize a new one.
          // This is used for Array types.
          schemaObject = new properties.objectType;
        }

        // Copy value to SchemaObject and set value to SchemaObject.
        _.each(value, function(v, k) {
          schemaObject[k] = v;
        });
        value = schemaObject;
      }

      // Otherwise, it's OK.
      return value;
      break;

    case 'date':
      // Reject if object, array or boolean.
      if(!_.isDate(value) && !_.isString(value) && !_.isNumber(value)) {
        throw new SetterError('Date type cannot typecast Array or Object types.', value, originalValue, properties);
      }

      // Attempt to parse string value with Date.parse (which returns number of milliseconds).
      if(_.isString(value)) {
        value = Date.parse(value);
      }

      // If is timestamp, convert to Date.
      if(_.isNumber(value)) {
        value = new Date((value + '').length > 10 ? value : value * 1000);
      }

      // If the date couldn't be parsed, do not modify index.
      if(value == 'Invalid Date' || !_.isDate(value)) {
        throw new SetterError('Could not parse date.', value, originalValue, properties);
      }

      // Transformation after typecasting but before validation and filters.
      if(properties.dateTransform) {
        value = properties.dateTransform.call(this, value, originalValue, properties);
      }

      return value;
      break;

    default:
      return value;
      break;
  }
};
Example #17
0
exports.isObjectID = function(obj){
  return _.isObject(obj) && obj.constructor && obj.constructor.name && obj.constructor.name === 'ObjectID';
};
Example #18
0
var normalizeProperties = function (properties)
{
    // Allow for shorthand type declaration:

    // index: Type is translated to index: {type: Type}
    if (properties && _.isUndefined(properties.type))
    {
        properties = { type: properties };
    }

    // Type may be an object with properties.
    // If "type.type" exists, we'll assume it's meant to be properties.
    // This means that shorthand objects can't use the "type" index.
    // If "type" is necessary, they must be wrapped in a SchemaObject.
    if (_.isObject(properties.type) && !_.isUndefined(properties.type.type))
    {
        _.each(properties.type, function (value, key)
        {
            if (_.isUndefined(properties[key]))
            {
                properties[key] = value;
            }
        });
        properties.type = properties.type.type;
    }

    // Null or undefined should be flexible and allow any value.
    if (properties.type === null || properties.type === undefined)
    {
        properties.type = 'any';

        // Convert object representation of type to lowercase string.
        // String is converted to 'string', Number to 'number', etc.
    } else if (properties.type.name)
    {
        properties.type = properties.type.name;
    }
    if (_.isString(properties.type))
    {
        properties.type = properties.type.toLowerCase();
    }

    // index: [Type] or index: [] is translated to index: {type: Array, arrayType: Type}
    if (_.isArray(properties.type))
    {
        if (_.size(properties.type))
        {
            // Properties will be normalized when array is initialized.
            properties.arrayType = properties.type[0];
        }
        properties.type = 'array';
    }

    // index: {} or index: SchemaObject is translated to index: {type: Object, objectType: Type}
    // SchemaObject factory is initialized when raw schema is provided.
    if (!_.isString(properties.type))
    {
        if (_.isFunction(properties.type))
        {
            properties.objectType = properties.type;
            properties.type = 'object';
        } else if (properties.type === {})
        {
            properties.type = 'object';
        } else if (_.isObject(properties.type) && _.size(properties.type))
        {
            properties.objectType = new SchemaObject(properties.type);
            properties.type = 'object';
        }
    }
    properties.toObject = properties.toObject || 'changed';
    return properties;
};