docs: function (values, schema, options, callback) {
      var newValues = {}
          , errors = []
          , modelList = find(schema)
          , val;
  
      for (var model in modelList) {
          if (_.isArray(modelList[model])) {
  
              if (values === undefined) {
                  val = undefined;
              }
              else {
                  val = values[model];
              }
  
              // Empty array defined in schema
              if (_.isEmpty(modelList[model])) {
                  if (val) {
                      newValues[model] = val;
                  }
              }
              else {
                  // Set value to empty array if empty given
                  if (val == undefined) {
                      if (options && options.partial == true) {
                          // Do nothing
                      }
                      else {
                          newValues[model] = [];
                      }
                  }
                  else {
                      // Sub model defined in schema
                      for (var thisSubSchema in modelList[model]) {
                          if (_.isArray(val)) {
                              for (var thisValue in val) {
  
                                  // Check if type array or plain array
                                  if (typeof val[thisValue] == "object") {
                                      modelCompare(val[thisValue], modelList[model][thisSubSchema], options, function (err, data) {
                                          if (err) {
                                              errors = _.union(errors, err);
                                          }
                                          if (data !== null) {
                                              if (!newValues[model]) {
                                                  newValues[model] = [];
                                              }
                                              newValues[model][thisValue] = data;
                                          }
                                      });
                                  }
                                  else {
                                      rulesMatch(thisValue, val[thisValue], modelList[model][thisSubSchema], options, function (err, data) {
                                          if (err) {
                                              errors.push(err);
                                          }
                                          if (data !== undefined) {
                                              if (!newValues[model]) {
                                                  newValues[model] = [];
                                              }
                                              newValues[model][thisValue] = data;
                                          }
                                      });
                                  }
                              }
                          }
                          else {
                              modelCompare(val, modelList[model][thisSubSchema], options, function (err, data) {
                                  if (err) {
                                      errors = _.union(errors, err);
                                  }
                                  if (data !== null) {
                                      newValues[model] = data;
                                  }
                              });
                          }
                      }
                  }
              }
          } else {
              // Check for definition of {} in model to allow any data for this node without validation
              if (_.isEmpty(modelList[model])) {
                  for (var index in values) {
                      var filter = new RegExp("^" + model);
                      if (index.match(filter)) {
                          newValues[index] = values[index];
                      }
                  }
              }
              else {
                  if (values === undefined) {
                      val = undefined;
                  }
                  else {
                      val = values[model];
                  }
  
                  rulesMatch(model, val, modelList[model], options, function (err, data) {
                      if (err) {
                          errors.push(err);
                      }
                      if (data !== undefined) {
                          newValues[model] = data;
                      }
                  });
              }
          }
      }
  
      if (_.isEmpty(errors)) {
          errors = null;
      }
      else {
          errors = {name: 'ValidationError', err: errors};
      }
      if (_.isEmpty(newValues)) {
          newValues = null;
      }
      callback(errors, newValues);
  }