<commit_before>(function() {

  /**
   * IsObject
   *
   * @param {object} input
   */
  var isObject = function(input) {
    return Object.prototype.toString.call(input) === '[object Object]';
  };

  /**
   * IsArray
   *
   * @param {object} input
   */
  var isArray = function(input) {
    return Object.prototype.toString.call(input) === '[object Array]';
  };

  /**
   * IsEmpty
   *  
   * Returns true if input is empty.
   *
   * @param {object} input
   */
  var isEmpty = function(input) {
    
    // Arrays and strings
    if (isArray(input)) {
      return input.length === 0;
    }

    // Objects
    if (isObject(input)) {
      for (var key in input) {
        if (hasOwnProperty.call(input, key)) {
          return false;
        }
      }
    }

    return true;

  };

  /**
   * Each
   *
   * Applies an iterator function to each item in an array or an object, in series.
   *
   * @param {object} list
   * @param {function} iterator
   * @param {function} callback
   */
  var each = function(list, iterator, callback) {

    /**
     * SyncEach
     *
     * @param {object} list
     * @param {function} iterator
     */
    var syncEach = function(list, iterator) {

      // If the list is an array
      if (isArray(list) && !isEmpty(list)) {
        for (var i = 0, len = list.length; i < len; i++) {
          iterator(i, list[i]);
        }
      }

      // If the list is an object
      if (isObject(list) && !isEmpty(list)) {
        for (var key in list) {
          if (list.hasOwnProperty(key)) {
            iterator(key, list[key]);
          }
        } 
      }

    };

    /**
     * AsyncEach
     * @param {object} list
     * @param {function} iterator
     * @param {function} callback
     */
    var asyncEach = function(list, iterator, callback) {

      var uncompleted;

      // If the list is an object
      if (isObject(list) && !isEmpty(list)) {
        uncompleted = Object.keys(list).length;

      // If the list is an array
      } else if (isArray(list) && !isEmpty(list)) {
        uncompleted = list.length;

      // If the list is not an array or an object
      } else {
        return callback();
      }

      /**
       * Next
       */
      var next = function(error) {
        uncompleted -= 1;
        if (error) {
          callback(error);
          callback = function() {};
        }
        if (!error && uncompleted === 0) {
          return callback();
        }
      };

      syncEach(list, function(key, value) {
        return iterator(key, value, next);
      });

    };

    if (typeof callback === 'undefined') {
      return syncEach.apply(this, arguments);
    } else {
      return asyncEach.apply(this, arguments);
    }

  };

  /**
   * Pluck
   *
   * Extracts a list of property values.
   *
   * @param {object} list
   * @param {string} propertyName
   */
  var pluck = function(list, propertyName) {
    var output = [];
    for (var i = 0, len = list.length; i < len; i++) {
      var property = list[i][propertyName];
      if (output.indexOf(property) === -1) {
        output.push(property);
      }
    }
    return output;
  };

  /**
   * Error
   *
   * @constructor
   */
  var Error = function() {
    this.length = 0;
  };

  Error.prototype.addError = function(error) {
    this[this.length] = error;
    this.length++;
  };

  /**
   * Error.getProperties
   * Error.getMessages
   */
  each({
    getProperties: 'property',
    getMessages: 'message'
  }, function(key, value) {
    Error.prototype[key] = function() {
      return pluck(this, value);
    };    
  });

  /**
   * Validator
   *
   * @constructor
   * @param {object} options
   */
  var Validator = function(options) {

    var self = this;

    // Errors
    this.Errors = new Error();

    // Options
    each([
      'singleError',
      'validators'
    ], function(key, value) {
      self[value] = options[value];
    });

  };

  /**
   * Validator.validateProperty
   *
   * @param {string} property
   * @param {object} propertyValidators
   * @param {string|object} propertyValue
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validateProperty = function(property, propertyValue, propertyValidators, callback) {

    // Reference na this
    var self = this;

    /**
     * Iterator
     *
     * @param {string} validatorName
     * @param {function} callback
     */
    var iterator = function(validatorName, validatorFn, callback) {
      if (propertyValidators[validatorName]) {
        validatorFn(property, propertyValue, propertyValidators[validatorName], propertyValidators, function(error) {

          if (error) {
            self.Errors.addError({
              property: property,
              propertyValue: propertyValue,
              validator: validatorName,
              validatorValue: propertyValidators[validatorName],
              message: error
            });
            return (self.singleError) ? callback(true) : callback();
          }

          return callback();

        });
      } else {
        return callback();
      }
    };

    if (propertyValidators.required !== true && typeof propertyValue === 'undefined') {
      return callback();
    } else {
      return each(self.validators, iterator, callback);
    }

  };

  /**
   * Validator.validate
   *
   * @param {object} instance
   * @param {object} schema
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validate = function(instance, schema, callback) {

    var self = this;

    return this.validateSchema(instance, schema, '', function(error) {
      return callback((self.Errors.length > 0) ? self.Errors : undefined);
    });

  };

  /**
   * Validator.validateSchema
   *
   * @param {object} instance
   * @param {object} schema
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validateSchema = function(instance, schema, path, callback) {

    var self = this;

    /**
     * {
     *   type: 'object',
     *   properties: {
     *     ... 
     *   }
     * }
     * — or —
     * {
     *   type: 'array',
     *   items: {
     *     ...
     * }
     */
    if (['object', 'array'].indexOf(schema.type) !== -1) {
      return self.validateProperty(path, instance, schema, function(error) {

        /**
         * {
         *   type: 'object',
         *   properties: {
         *     ... 
         *   }
         * }
         */
        if (schema.properties) {
          return each(schema.properties, function(property, propertyValidators, callback) {
            
            var isObject = propertyValidators.type === 'object' && propertyValidators.properties,
                isArray =  propertyValidators.type === 'array';

            // Get the value of property (instance[property])
            var propertyValue = self.getProperty(instance, property);

            // Compose the property path
            var propertyPath = (path.length === 0) ? property : path + '.' + property;

            /**
             * {
             *   type: 'object',
             *   properties: {
             *     user: {
             *       type: 'object',
             *       properties: {
             *         ...
             *       }
             *     }
             *   }
             * }
             */
            if (isObject || isArray)  {
              return self.validateSchema(propertyValue, schema.properties[property], propertyPath, callback);
            } else {
              return self.validateProperty(propertyPath, propertyValue, propertyValidators, callback);
            }

          }, callback);

        /**
         * {
         *   type: 'array',
         *   items: {
         *     type: 'string'
         *     ... 
         *   }
         * }
         */
        } else if (schema.items) {

          if (instance && !isEmpty(instance)) {

            /**
             * {
             *   type: 'array',
             *   items: {
             *     type: 'object'
             *   }
             * }
             * — or —
             * {
             *   type: 'array',
             *   items: {
             *     type: 'array'
             *   }
             * }
             */
            if (['object', 'array'].indexOf(schema.items.type) !== -1) {
              return each(instance, function(index, propertyValue, callback) {
                var propertyPath = path + '[' + index + ']';
                return self.validateSchema(propertyValue, schema.items, propertyPath, callback);
              }, callback);

            /*
             * {
             *   type: 'array',
             *   items: {
             *     type: 'string'
             *   }
             * }
             */
            } else {
              return each(instance, function(index, propertyValue, callback) {
                var propertyPath = path + '[' + index + ']';
                return self.validateProperty(propertyPath, propertyValue, schema.items, callback);
              }, callback);
            }

          } else {
            return callback();
          } 

        /**
         * {
         *   type: 'array'
         * }
         * — or —
         * {
         *   type: 'object'
         * }
         */
        } else {
          return callback();
        }

      });

    /**
     * {
     *   type: 'string',
     *   length: ...
     * }
     */
    } else {
      return self.validateProperty(path, instance, schema, callback);
    }

  };

  /**
   * GetProperty
   *
   * @param {object} source
   * @param {string} property
   */
  Validator.prototype.getProperty = function(source, property) {
    if (!source) {
      return undefined;
    } else {
      return source[property];
    }
  };

  /**
   * Validators
   */
  var validators = {

    /**
     * Required
     */
    'required': function(property, propertyValue, validator, propertyValidators, callback) {
      if (validator && !propertyValue) {
        return callback('‘' + property + '’ is required');
      } else {
        return callback();
      }
    },

    /**
     * Type
     */
    'type': (function() {
      
      var types = {
        'object': function(input) {
          return Object.prototype.toString.call(input) === '[object Object]';
        },
        'array': function(input) {
          return Object.prototype.toString.call(input) === '[object Array]';
        },
        'integer': function(input) {
          return (typeof input === 'number') && input % 1 === 0;
        }
      };

      // Generate the rest of type checkers
      [
        'string',
        'number',
        'function',
        'boolean'
      ].forEach(function(type) {
        types[type] = function() {
          return typeof arguments[0] === type;
        };
      });

      return function(property, propertyValue, validator, propertyValidators, callback) {

        /**
         * {
         *   type: ['string', 'number']
         * }
         */
        if (Object.prototype.toString.call(validator) === '[object Array]') {
          var noError = options.some(function(type) {
            return types[type](propertyValue);
          });
          return (noError) ? callback() : callback('‘' + property + '’ must be ' + validator.join(' or '));

        /**
         * {
         *   type: 'string'
         * }
         */
        } else {
          return (types[validator](propertyValue)) ? callback() : callback('‘' + property + '’ must be ' + validator);
        }

      };

    }()),

    /**
     * Format
     */
    'format': (function() {

      /**
       * Formats
       */
      var formats = {
        'alpha': function(input) {
          return (typeof input === 'string' && input.match(/^[a-zA-Z]+$/));<commit_msg>options doesn't exist, but the validator does. caused crash.<commit_after>(function() {

  /**
   * IsObject
   *
   * @param {object} input
   */
  var isObject = function(input) {
    return Object.prototype.toString.call(input) === '[object Object]';
  };

  /**
   * IsArray
   *
   * @param {object} input
   */
  var isArray = function(input) {
    return Object.prototype.toString.call(input) === '[object Array]';
  };

  /**
   * IsEmpty
   *  
   * Returns true if input is empty.
   *
   * @param {object} input
   */
  var isEmpty = function(input) {
    
    // Arrays and strings
    if (isArray(input)) {
      return input.length === 0;
    }

    // Objects
    if (isObject(input)) {
      for (var key in input) {
        if (hasOwnProperty.call(input, key)) {
          return false;
        }
      }
    }

    return true;

  };

  /**
   * Each
   *
   * Applies an iterator function to each item in an array or an object, in series.
   *
   * @param {object} list
   * @param {function} iterator
   * @param {function} callback
   */
  var each = function(list, iterator, callback) {

    /**
     * SyncEach
     *
     * @param {object} list
     * @param {function} iterator
     */
    var syncEach = function(list, iterator) {

      // If the list is an array
      if (isArray(list) && !isEmpty(list)) {
        for (var i = 0, len = list.length; i < len; i++) {
          iterator(i, list[i]);
        }
      }

      // If the list is an object
      if (isObject(list) && !isEmpty(list)) {
        for (var key in list) {
          if (list.hasOwnProperty(key)) {
            iterator(key, list[key]);
          }
        } 
      }

    };

    /**
     * AsyncEach
     * @param {object} list
     * @param {function} iterator
     * @param {function} callback
     */
    var asyncEach = function(list, iterator, callback) {

      var uncompleted;

      // If the list is an object
      if (isObject(list) && !isEmpty(list)) {
        uncompleted = Object.keys(list).length;

      // If the list is an array
      } else if (isArray(list) && !isEmpty(list)) {
        uncompleted = list.length;

      // If the list is not an array or an object
      } else {
        return callback();
      }

      /**
       * Next
       */
      var next = function(error) {
        uncompleted -= 1;
        if (error) {
          callback(error);
          callback = function() {};
        }
        if (!error && uncompleted === 0) {
          return callback();
        }
      };

      syncEach(list, function(key, value) {
        return iterator(key, value, next);
      });

    };

    if (typeof callback === 'undefined') {
      return syncEach.apply(this, arguments);
    } else {
      return asyncEach.apply(this, arguments);
    }

  };

  /**
   * Pluck
   *
   * Extracts a list of property values.
   *
   * @param {object} list
   * @param {string} propertyName
   */
  var pluck = function(list, propertyName) {
    var output = [];
    for (var i = 0, len = list.length; i < len; i++) {
      var property = list[i][propertyName];
      if (output.indexOf(property) === -1) {
        output.push(property);
      }
    }
    return output;
  };

  /**
   * Error
   *
   * @constructor
   */
  var Error = function() {
    this.length = 0;
  };

  Error.prototype.addError = function(error) {
    this[this.length] = error;
    this.length++;
  };

  /**
   * Error.getProperties
   * Error.getMessages
   */
  each({
    getProperties: 'property',
    getMessages: 'message'
  }, function(key, value) {
    Error.prototype[key] = function() {
      return pluck(this, value);
    };    
  });

  /**
   * Validator
   *
   * @constructor
   * @param {object} options
   */
  var Validator = function(options) {

    var self = this;

    // Errors
    this.Errors = new Error();

    // Options
    each([
      'singleError',
      'validators'
    ], function(key, value) {
      self[value] = options[value];
    });

  };

  /**
   * Validator.validateProperty
   *
   * @param {string} property
   * @param {object} propertyValidators
   * @param {string|object} propertyValue
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validateProperty = function(property, propertyValue, propertyValidators, callback) {

    // Reference na this
    var self = this;

    /**
     * Iterator
     *
     * @param {string} validatorName
     * @param {function} callback
     */
    var iterator = function(validatorName, validatorFn, callback) {
      if (propertyValidators[validatorName]) {
        validatorFn(property, propertyValue, propertyValidators[validatorName], propertyValidators, function(error) {

          if (error) {
            self.Errors.addError({
              property: property,
              propertyValue: propertyValue,
              validator: validatorName,
              validatorValue: propertyValidators[validatorName],
              message: error
            });
            return (self.singleError) ? callback(true) : callback();
          }

          return callback();

        });
      } else {
        return callback();
      }
    };

    if (propertyValidators.required !== true && typeof propertyValue === 'undefined') {
      return callback();
    } else {
      return each(self.validators, iterator, callback);
    }

  };

  /**
   * Validator.validate
   *
   * @param {object} instance
   * @param {object} schema
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validate = function(instance, schema, callback) {

    var self = this;

    return this.validateSchema(instance, schema, '', function(error) {
      return callback((self.Errors.length > 0) ? self.Errors : undefined);
    });

  };

  /**
   * Validator.validateSchema
   *
   * @param {object} instance
   * @param {object} schema
   * @param {boolean} singleError
   * @param {function} callback
   */
  Validator.prototype.validateSchema = function(instance, schema, path, callback) {

    var self = this;

    /**
     * {
     *   type: 'object',
     *   properties: {
     *     ... 
     *   }
     * }
     * — or —
     * {
     *   type: 'array',
     *   items: {
     *     ...
     * }
     */
    if (['object', 'array'].indexOf(schema.type) !== -1) {
      return self.validateProperty(path, instance, schema, function(error) {

        /**
         * {
         *   type: 'object',
         *   properties: {
         *     ... 
         *   }
         * }
         */
        if (schema.properties) {
          return each(schema.properties, function(property, propertyValidators, callback) {
            
            var isObject = propertyValidators.type === 'object' && propertyValidators.properties,
                isArray =  propertyValidators.type === 'array';

            // Get the value of property (instance[property])
            var propertyValue = self.getProperty(instance, property);

            // Compose the property path
            var propertyPath = (path.length === 0) ? property : path + '.' + property;

            /**
             * {
             *   type: 'object',
             *   properties: {
             *     user: {
             *       type: 'object',
             *       properties: {
             *         ...
             *       }
             *     }
             *   }
             * }
             */
            if (isObject || isArray)  {
              return self.validateSchema(propertyValue, schema.properties[property], propertyPath, callback);
            } else {
              return self.validateProperty(propertyPath, propertyValue, propertyValidators, callback);
            }

          }, callback);

        /**
         * {
         *   type: 'array',
         *   items: {
         *     type: 'string'
         *     ... 
         *   }
         * }
         */
        } else if (schema.items) {

          if (instance && !isEmpty(instance)) {

            /**
             * {
             *   type: 'array',
             *   items: {
             *     type: 'object'
             *   }
             * }
             * — or —
             * {
             *   type: 'array',
             *   items: {
             *     type: 'array'
             *   }
             * }
             */
            if (['object', 'array'].indexOf(schema.items.type) !== -1) {
              return each(instance, function(index, propertyValue, callback) {
                var propertyPath = path + '[' + index + ']';
                return self.validateSchema(propertyValue, schema.items, propertyPath, callback);
              }, callback);

            /*
             * {
             *   type: 'array',
             *   items: {
             *     type: 'string'
             *   }
             * }
             */
            } else {
              return each(instance, function(index, propertyValue, callback) {
                var propertyPath = path + '[' + index + ']';
                return self.validateProperty(propertyPath, propertyValue, schema.items, callback);
              }, callback);
            }

          } else {
            return callback();
          } 

        /**
         * {
         *   type: 'array'
         * }
         * — or —
         * {
         *   type: 'object'
         * }
         */
        } else {
          return callback();
        }

      });

    /**
     * {
     *   type: 'string',
     *   length: ...
     * }
     */
    } else {
      return self.validateProperty(path, instance, schema, callback);
    }

  };

  /**
   * GetProperty
   *
   * @param {object} source
   * @param {string} property
   */
  Validator.prototype.getProperty = function(source, property) {
    if (!source) {
      return undefined;
    } else {
      return source[property];
    }
  };

  /**
   * Validators
   */
  var validators = {

    /**
     * Required
     */
    'required': function(property, propertyValue, validator, propertyValidators, callback) {
      if (validator && !propertyValue) {
        return callback('‘' + property + '’ is required');
      } else {
        return callback();
      }
    },

    /**
     * Type
     */
    'type': (function() {
      
      var types = {
        'object': function(input) {
          return Object.prototype.toString.call(input) === '[object Object]';
        },
        'array': function(input) {
          return Object.prototype.toString.call(input) === '[object Array]';
        },
        'integer': function(input) {
          return (typeof input === 'number') && input % 1 === 0;
        }
      };

      // Generate the rest of type checkers
      [
        'string',
        'number',
        'function',
        'boolean'
      ].forEach(function(type) {
        types[type] = function() {
          return typeof arguments[0] === type;
        };
      });

      return function(property, propertyValue, validator, propertyValidators, callback) {

        /**
         * {
         *   type: ['string', 'number']
         * }
         */
        if (Object.prototype.toString.call(validator) === '[object Array]') {
          var noError = validator.some(function(type) {
            return types[type](propertyValue);
          });
          return (noError) ? callback() : callback('‘' + property + '’ must be ' + validator.join(' or '));

        /**
         * {
         *   type: 'string'
         * }
         */
        } else {
          return (types[validator](propertyValue)) ? callback() : callback('‘' + property + '’ must be ' + validator);
        }

      };

    }()),

    /**
     * Format
     */
    'format': (function() {

      /**
       * Formats
       */
      var formats = {
        'alpha': function(input) {
          return (typeof input === 'string' && input.match(/^[a-zA-Z]+$/));
{'fraction_non_alphanumeric': 0.14092232395257584, 'fraction_numerical': 0.0011813847516982405, 'mean_word_length': 1.5576777813747706, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1012565', 'n_tokens_mistral': 6829, 'n_tokens_neox': 6647, 'n_words': 1487}