properties (value, schema, opts) {
    opts || (opts = {})

    if (utils.isArray(value)) {
      return
    }

    // Can be a boolean or an object
    // Technically the default is an "empty schema", but here "true" is
    // functionally the same
    const additionalProperties = schema.additionalProperties === undefined ? true : schema.additionalProperties
    const validated = []
    // "p": The property set from "properties".
    // Default is an object
    const properties = schema.properties || {}
    // "pp": The property set from "patternProperties".
    // Default is an object
    const patternProperties = schema.patternProperties || {}
    let errors = []

    utils.forOwn(properties, function (_schema, prop) {
      opts.prop = prop
      errors = errors.concat(validate(value[prop], _schema, opts) || [])
      validated.push(prop)
    })

    const toValidate = utils.omit(value, validated)
    utils.forOwn(patternProperties, function (_schema, pattern) {
      utils.forOwn(toValidate, function (undef, prop) {
        if (prop.match(pattern)) {
          opts.prop = prop
          errors = errors.concat(validate(value[prop], _schema, opts) || [])
          validated.push(prop)
        }
      })
    })
    const keys = Object.keys(utils.omit(value, validated))
    // If "s" is not empty, validation fails
    if (additionalProperties === false) {
      if (keys.length) {
        const origProp = opts.prop
        opts.prop = ''
        addError(`extra fields: ${keys.join(', ')}`, 'no extra fields', opts, errors)
        opts.prop = origProp
      }
    } else if (utils.isObject(additionalProperties)) {
      // Otherwise, validate according to provided schema
      keys.forEach(function (prop) {
        opts.prop = prop
        errors = errors.concat(validate(value[prop], additionalProperties, opts) || [])
      })
    }
    return errors.length ? errors : undefined
  }
Validates the provided object's properties against a map of values defined in the Schema's `properties` keyword.
Validation succeeds if the object's property are valid with each of the schema's in the provided map.
Validation also depends on the additionalProperties and or patternProperties.

see http://json-schema.org/latest/json-schema-validation.html#anchor64 for more info.

@name Schema.validationKeywords.properties
@method
@param {*} value Object to be validated.
@param {object} schema Schema containing the `properties` keyword.
@param {object} [opts] Configuration options.
@returns {(array|undefined)} Array of errors or `undefined` if valid.