<commit_before>if (typeof require !== 'undefined') {
  var _ = require("underscore");
}

var AvroSpec = {
  PrimitiveTypes: ['null', 'boolean', 'int', 'long', 'float', 'double', 'bytes', 'string'],
  ComplexTypes: ['record', 'enum', 'array', 'map', 'union', 'fixed']
};
AvroSpec.Types = AvroSpec.PrimitiveTypes.concat(AvroSpec.ComplexTypes);

var InvalidSchemaError = function(msg) { return new Error('InvalidSchemaError: ' + msg); };
var InvalidProtocolError = function(msg) { return new Error('InvalidProtocolError: ' + msg); };
var ValidationError = function(msg) { return new Error('ValidationError: ' + msg); };
var ProtocolValidationError = function(msg) { return new Error('ProtocolValidationError: ' + msg); };

function Record(name, namespace, fields) {
  function validateArgs(name, namespace, fields) {
    if (!_.isString(name)) {
      throw new InvalidSchemaError('Record name must be string');
    }

    if (!_.isNull(namespace) && !_.isUndefined(namespace) && !_.isString(namespace)) {
      throw new InvalidSchemaError('Record namespace must be string or null');
    }

    if (!_.isArray(fields)) {
      throw new InvalidSchemaError('Record name must be string');
    }
  }

  validateArgs(name, namespace, fields);

  this.name = name;
  this.namespace = namespace;
  this.fields = fields;
}

function makeFullyQualifiedTypeName(schema, namespace) {
  var typeName = null;
  if (_.isString(schema)) {
    typeName = schema;
  } else if (_.isObject(schema)) {
    if (_.isString(schema.namespace)) {
      namespace = schema.namespace;
    }
    if (_.isString(schema.name)) {
      typeName = schema.name;
    } else if (_.isString(schema.type)) {
      typeName = schema.type;
    }
  } else {
    throw new InvalidSchemaError('unable to determine fully qualified type name from schema ' + JSON.stringify(schema) + ' in namespace ' + namespace);
  }

  if (!_.isString(typeName)) {
    throw new InvalidSchemaError('unable to determine type name from schema ' + JSON.stringify(schema) + ' in namespace ' + namespace);
  }

  if (typeName.indexOf('.') !== -1) {
    return typeName;
  } else if (_.contains(AvroSpec.PrimitiveTypes, typeName)) {
    return typeName;
  } else if (_.isString(namespace)) {
    return namespace + '.' + typeName;
  } else {
    return typeName;
  }
}

function Union(typeSchemas, namespace) {
  this.branchNames = function() {
    return _.map(typeSchemas, function(typeSchema) { return makeFullyQualifiedTypeName(typeSchema, namespace); });
  };

  function validateArgs(typeSchemas) {
    if (!_.isArray(typeSchemas) || _.isEmpty(typeSchemas)) {
      throw new InvalidSchemaError('Union must have at least 1 branch');
    }
  }

  validateArgs(typeSchemas);

  this.typeSchemas = typeSchemas;
  this.namespace = namespace;
}

function Enum(symbols) {

  function validateArgs(symbols) {
    if (!_.isArray(symbols)) {
      throw new InvalidSchemaError('Enum must have array of symbols, got ' + JSON.stringify(symbols));
    }
    if (!_.all(symbols, function(symbol) { return _.isString(symbol); })) {
      throw new InvalidSchemaError('Enum symbols must be strings, got ' + JSON.stringify(symbols));
    }
  }

  validateArgs(symbols);

  this.symbols = symbols;
}

function AvroArray(itemSchema) {

  function validateArgs(itemSchema) {
    if (_.isNull(itemSchema) || _.isUndefined(itemSchema)) {
      throw new InvalidSchemaError('Array "items" schema should not be null or undefined');
    }
  }

  validateArgs(itemSchema);

  this.itemSchema = itemSchema;
}

function Map(valueSchema) {

  function validateArgs(valueSchema) {
    if (_.isNull(valueSchema) || _.isUndefined(valueSchema)) {
      throw new InvalidSchemaError('Map "values" schema should not be null or undefined');
    }
  }

  validateArgs(valueSchema);

  this.valueSchema = valueSchema;
}

function Field(name, schema) {
  function validateArgs(name, schema) {
    if (!_.isString(name)) {
      throw new InvalidSchemaError('Field name must be string');
    }
  }

  this.name = name;
  this.schema = schema;
}

function Primitive(type) {
  function validateArgs(type) {
    if (!_.isString(type)) {
      throw new InvalidSchemaError('Primitive type name must be a string');
    }

    if (!_.contains(AvroSpec.PrimitiveTypes, type)) {
      throw new InvalidSchemaError('Primitive type must be one of: ' + JSON.stringify(AvroSpec.PrimitiveTypes) + '; got ' + type);
    }
  }

  validateArgs(type);

  this.type = type;
}

function Validator(schema, namespace, namedTypes) {
  this.validate = function(obj) {
    return _validate(this.schema, obj);
  };

  var _validate = function(schema, obj) {
    if (schema instanceof Record) {
      return _validateRecord(schema, obj);
    } else if (schema instanceof Union) {
      return _validateUnion(schema, obj);
    } else if (schema instanceof Enum) {
      return _validateEnum(schema, obj);
    } else if (schema instanceof AvroArray) {
      return _validateArray(schema, obj);
    } else if (schema instanceof Map) {
      return _validateMap(schema, obj);
    } else if (schema instanceof Primitive) {
      return _validatePrimitive(schema, obj);
    } else {
      throw new InvalidSchemaError('validation not yet implemented: ' + JSON.stringify(schema));
    }
  };

  var _validateRecord = function(schema, obj) {
    if (!_.isObject(obj) || _.isArray(obj)) {
      throw new ValidationError('Expected record Javascript type to be non-array object, got ' + JSON.stringify(obj));
    }

    var schemaFieldNames = _.pluck(schema.fields, 'name');
    var objFieldNames = _.keys(obj);
    if (!_.isEqual(schemaFieldNames, objFieldNames)) {
      throw new ValidationError('Expected record fields ' + JSON.stringify(schemaFieldNames) + '; got ' + JSON.stringify(objFieldNames));
    }

    return _.all(schema.fields, function(field) {
      return _validate(field.schema, obj[field.name]);
    });
  };

  var _validateUnion = function(schema, obj) {
    if (_.isObject(obj)) {
      if (_.isArray(obj)) {
        throw new ValidationError('Expected union Javascript type to be non-array object (or null), got ' + JSON.stringify(obj));
      } else if (_.size(obj) !== 1) {
        throw new ValidationError('Expected union Javascript object to be object with exactly 1 key (or null), got ' + JSON.stringify(obj));
      } else {
        var unionBranch = _.keys(obj)[0];
        if (unionBranch === "") {
          throw new ValidationError('Expected union Javascript object to contain non-empty string branch, got ' + JSON.stringify(obj));
        }
        if (_.contains(schema.branchNames(), unionBranch)) {
          return true;
        } else {
          throw new ValidationError('Expected union branch to be one of ' + JSON.stringify(schema.branchNames()) + '; got ' + JSON.stringify(unionBranch));
        }
      }
    } else if (_.isNull(obj)) {
      if (_.contains(schema.branchNames(), 'null')) {
        return true;
      } else {
        throw new ValidationError('Expected union branch to be one of ' + JSON.stringify(schema.branchNames()) + '; got ' + JSON.stringify(obj));
      }
    } else {
      throw new ValidationError('Expected union Javascript object to be non-array object of size 1 or null, got ' + JSON.stringify(obj));
    }
  };

  var _validateEnum = function(schema, obj) {
    if (_.isString(obj)) {
      if (_.contains(schema.symbols, obj)) {
        return true;
      } else {
        throw new ValidationError('Expected enum value to be one of ' + JSON.stringify(schema.symbols) + '; got ' + JSON.stringify(obj));
      }
    } else {
      throw new ValidationError('Expected enum Javascript object to be string, got ' + JSON.stringify(obj));
    }
  };

  var _validateArray = function(schema, obj) {
    if (_.isArray(obj)) {
      return _.all(obj, function(member) { return _validate(schema.itemSchema, member); });
    } else {
      throw new ValidationError('Expected array Javascript object to be array, got ' + JSON.stringify(obj));
    }
  };

  var _validateMap = function(schema, obj) {
    if (_.isObject(obj) && !_.isArray(obj)) {
      return _.all(obj, function(value) { return _validate(schema.valueSchema, value); });
    } else if (_.isArray(obj)) {
      throw new ValidationError('Expected map Javascript object to be non-array object, got array ' + JSON.stringify(obj));
    } else {
      throw new ValidationError('Expected map Javascript object to be non-array object, got ' + JSON.stringify(obj));
    }
  };

  var _validatePrimitive = function(schema, obj) {
    switch (schema.type) {
      case 'null':
        if (_.isNull(obj) || _.isUndefined(obj)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript null or undefined for Avro null, got ' + JSON.stringify(obj));
        }
        break;
      case 'boolean':
        if (_.isBoolean(obj)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript boolean for Avro boolean, got ' + JSON.stringify(obj));
        }
        break;
      case 'int':
        if (_.isNumber(obj) && Math.floor(obj) === obj && Math.abs(obj) <= Math.pow(2, 31)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript int32 number for Avro int, got ' + JSON.stringify(obj));
        }
        break;
      case 'long':
        if (_.isNumber(obj) && Math.floor(obj) === obj && Math.abs(obj) <= Math.pow(2, 63)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript int64 number for Avro long, got ' + JSON.stringify(obj));
        }
        break;
      case 'float':
        if (_.isNumber(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript float number for Avro float, got ' + JSON.stringify(obj));
        }
        break;
      case 'double':
        if (_.isNumber(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript double number for Avro double, got ' + JSON.stringify(obj));
        }
        break;
      case 'bytes':
        throw new InvalidSchemaError('not yet implemented: ' + schema.type);
      case 'string':
        if (_.isString(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript string for Avro string, got ' + JSON.stringify(obj));
        }
        break;
      default:
        throw new InvalidSchemaError('unrecognized primitive type: ' + schema.type);
    }
  };

  // TODO: namespace handling is rudimentary. multiple namespaces within a certain nested schema definition
  // are probably buggy.
  var _namedTypes = namedTypes || {};
  var _saveNamedType = function(fullyQualifiedTypeName, schema) {
    if (_.has(_namedTypes, fullyQualifiedTypeName)) {
      if (!_.isEqual(_namedTypes[fullyQualifiedTypeName], schema)) {
        throw new InvalidSchemaError('conflicting definitions for type ' + fullyQualifiedTypeName + ': ' + JSON.stringify(_namedTypes[fullyQualifiedTypeName]) + ' and ' + JSON.stringify(schema));
      }
    } else {
      _namedTypes[fullyQualifiedTypeName] = schema;
    }
  };

  var _lookupTypeByFullyQualifiedName = function(fullyQualifiedTypeName) {
    if (_.has(_namedTypes, fullyQualifiedTypeName)) {
      return _namedTypes[fullyQualifiedTypeName];
    } else {
      return null;
    }
  };

  var _parseNamedType = function(schema, namespace) {
    if (_.contains(AvroSpec.PrimitiveTypes, schema)) {
      return new Primitive(schema);
    } else if (!_.isNull(_lookupTypeByFullyQualifiedName(makeFullyQualifiedTypeName(schema, namespace)))) {
      return _lookupTypeByFullyQualifiedName(makeFullyQualifiedTypeName(schema, namespace));
    } else {
      throw new InvalidSchemaError('unknown type name: ' + JSON.stringify(schema) + '; known type names are ' + JSON.stringify(_.keys(_namedTypes)));
    }
  };

  var _parseSchema = function(schema, parentSchema, namespace) {
    if (_.isNull(schema) || _.isUndefined(schema)) {
      throw new InvalidSchemaError('schema is null, in parentSchema: ' + JSON.stringify(parentSchema));
    } else if (_.isString(schema)) {
      return _parseNamedType(schema, namespace);
    } else if (_.isObject(schema) && !_.isArray(schema)) {
      if (schema.type === 'record') {
        var newRecord = new Record(schema.name, schema.namespace, _.map(schema.fields, function(field) {
          return new Field(field.name, _parseSchema(field.type, schema, schema.namespace || namespace));
        }));
        _saveNamedType(makeFullyQualifiedTypeName(schema, namespace), newRecord);
        return newRecord;
      } else if (schema.type === 'enum') {
        if (_.has(schema, 'symbols')) {
          var newEnum = new Enum(schema.symbols);
          _saveNamedType(makeFullyQualifiedTypeName(schema, namespace), newEnum);
          return newEnum;
        } else {
          throw new InvalidSchemaError('enum must specify symbols, got ' + JSON.stringify(schema));
        }
      } else if (schema.type === 'array') {
        if (_.has(schema, 'items')) {
          return new AvroArray(_parseSchema(schema.items, schema, namespace));
        } else {
          throw new InvalidSchemaError('array must specify "items" schema, got ' + JSON.stringify(schema));
        }
      } else if (schema.type === 'map') {
        if (_.has(schema, 'values')) {
          return new Map(_parseSchema(schema.values, schema, namespace));
        } else {
          throw new InvalidSchemaError('map must specify "values" schema, got ' + JSON.stringify(schema));
        }
      } else if (_.has(schema, 'type') && _.contains(AvroSpec.PrimitiveTypes, schema.type)) {
        return _parseNamedType(schema.type, namespace);
      } else {
        throw new InvalidSchemaError('not yet implemented: ' + schema.type);
      }
    } else if (_.isArray(schema)) {
      if (_.isEmpty(schema)) {
        throw new InvalidSchemaError('unions must have at least 1 branch');
      }
      var branchTypes = _.map(schema, function(branchType) { return _parseSchema(branchType, schema, namespace); });
      return new Union(branchTypes, namespace);
    } else {
      throw new InvalidSchemaError('unexpected Javascript type for schema: ' + (typeof schema));
    }
  };

  this.rawSchema = schema;
  this.schema = _parseSchema(schema, namespace);
}

Validator.validate = function(schema, obj) {
  return (new Validator(schema)).validate(obj);
};

function ProtocolValidator(protocol) {
  this.validate = function(typeName, obj) {
    var fullyQualifiedTypeName = makeFullyQualifiedTypeName(typeName, protocol.namespace);
    if (!_.has(_typeSchemaValidators, fullyQualifiedTypeName)) {
      throw new ProtocolValidationError('Protocol does not contain definition for type ' + JSON.stringify(fullyQualifiedTypeName) + ' (fully qualified from input "' + typeName + '"); known types are ' + JSON.stringify(_.keys(_typeSchemaValidators)));
    }
    return _typeSchemaValidators[fullyQualifiedTypeName].validate(obj);
  };

  var _typeSchemaValidators = {};
  var _initSchemaValidators = function(protocol) {
    var namedTypes = {};
    if (!_.has(protocol, 'protocol') || !_.isString(protocol.protocol)) {
      throw new InvalidProtocolError('Protocol must contain a "protocol" attribute with a string value');
    }
    if (_.isArray(protocol.types)) {
      _.each(protocol.types, function(typeSchema) {
        var schemaValidator = new Validator(typeSchema, protocol.namespace, namedTypes);
        var fullyQualifiedTypeName = makeFullyQualifiedTypeName(typeSchema, protocol.namespace);
        _typeSchemaValidators[fullyQualifiedTypeName] = schemaValidator;
      });
    }
  };

  _initSchemaValidators(protocol);
}

ProtocolValidator.validate = function(protocol, typeName, obj) {
  return (new ProtocolValidator(protocol)).validate(typeName, obj);
};

exports['Validator'] = Validator;
exports['ProtocolValidator'] = ProtocolValidator;
<commit_msg>wrap exports in if-block to allow usage in both node.js and browser<commit_after>if (typeof require !== 'undefined') {
  var _ = require("underscore");
}

var AvroSpec = {
  PrimitiveTypes: ['null', 'boolean', 'int', 'long', 'float', 'double', 'bytes', 'string'],
  ComplexTypes: ['record', 'enum', 'array', 'map', 'union', 'fixed']
};
AvroSpec.Types = AvroSpec.PrimitiveTypes.concat(AvroSpec.ComplexTypes);

var InvalidSchemaError = function(msg) { return new Error('InvalidSchemaError: ' + msg); };
var InvalidProtocolError = function(msg) { return new Error('InvalidProtocolError: ' + msg); };
var ValidationError = function(msg) { return new Error('ValidationError: ' + msg); };
var ProtocolValidationError = function(msg) { return new Error('ProtocolValidationError: ' + msg); };

function Record(name, namespace, fields) {
  function validateArgs(name, namespace, fields) {
    if (!_.isString(name)) {
      throw new InvalidSchemaError('Record name must be string');
    }

    if (!_.isNull(namespace) && !_.isUndefined(namespace) && !_.isString(namespace)) {
      throw new InvalidSchemaError('Record namespace must be string or null');
    }

    if (!_.isArray(fields)) {
      throw new InvalidSchemaError('Record name must be string');
    }
  }

  validateArgs(name, namespace, fields);

  this.name = name;
  this.namespace = namespace;
  this.fields = fields;
}

function makeFullyQualifiedTypeName(schema, namespace) {
  var typeName = null;
  if (_.isString(schema)) {
    typeName = schema;
  } else if (_.isObject(schema)) {
    if (_.isString(schema.namespace)) {
      namespace = schema.namespace;
    }
    if (_.isString(schema.name)) {
      typeName = schema.name;
    } else if (_.isString(schema.type)) {
      typeName = schema.type;
    }
  } else {
    throw new InvalidSchemaError('unable to determine fully qualified type name from schema ' + JSON.stringify(schema) + ' in namespace ' + namespace);
  }

  if (!_.isString(typeName)) {
    throw new InvalidSchemaError('unable to determine type name from schema ' + JSON.stringify(schema) + ' in namespace ' + namespace);
  }

  if (typeName.indexOf('.') !== -1) {
    return typeName;
  } else if (_.contains(AvroSpec.PrimitiveTypes, typeName)) {
    return typeName;
  } else if (_.isString(namespace)) {
    return namespace + '.' + typeName;
  } else {
    return typeName;
  }
}

function Union(typeSchemas, namespace) {
  this.branchNames = function() {
    return _.map(typeSchemas, function(typeSchema) { return makeFullyQualifiedTypeName(typeSchema, namespace); });
  };

  function validateArgs(typeSchemas) {
    if (!_.isArray(typeSchemas) || _.isEmpty(typeSchemas)) {
      throw new InvalidSchemaError('Union must have at least 1 branch');
    }
  }

  validateArgs(typeSchemas);

  this.typeSchemas = typeSchemas;
  this.namespace = namespace;
}

function Enum(symbols) {

  function validateArgs(symbols) {
    if (!_.isArray(symbols)) {
      throw new InvalidSchemaError('Enum must have array of symbols, got ' + JSON.stringify(symbols));
    }
    if (!_.all(symbols, function(symbol) { return _.isString(symbol); })) {
      throw new InvalidSchemaError('Enum symbols must be strings, got ' + JSON.stringify(symbols));
    }
  }

  validateArgs(symbols);

  this.symbols = symbols;
}

function AvroArray(itemSchema) {

  function validateArgs(itemSchema) {
    if (_.isNull(itemSchema) || _.isUndefined(itemSchema)) {
      throw new InvalidSchemaError('Array "items" schema should not be null or undefined');
    }
  }

  validateArgs(itemSchema);

  this.itemSchema = itemSchema;
}

function Map(valueSchema) {

  function validateArgs(valueSchema) {
    if (_.isNull(valueSchema) || _.isUndefined(valueSchema)) {
      throw new InvalidSchemaError('Map "values" schema should not be null or undefined');
    }
  }

  validateArgs(valueSchema);

  this.valueSchema = valueSchema;
}

function Field(name, schema) {
  function validateArgs(name, schema) {
    if (!_.isString(name)) {
      throw new InvalidSchemaError('Field name must be string');
    }
  }

  this.name = name;
  this.schema = schema;
}

function Primitive(type) {
  function validateArgs(type) {
    if (!_.isString(type)) {
      throw new InvalidSchemaError('Primitive type name must be a string');
    }

    if (!_.contains(AvroSpec.PrimitiveTypes, type)) {
      throw new InvalidSchemaError('Primitive type must be one of: ' + JSON.stringify(AvroSpec.PrimitiveTypes) + '; got ' + type);
    }
  }

  validateArgs(type);

  this.type = type;
}

function Validator(schema, namespace, namedTypes) {
  this.validate = function(obj) {
    return _validate(this.schema, obj);
  };

  var _validate = function(schema, obj) {
    if (schema instanceof Record) {
      return _validateRecord(schema, obj);
    } else if (schema instanceof Union) {
      return _validateUnion(schema, obj);
    } else if (schema instanceof Enum) {
      return _validateEnum(schema, obj);
    } else if (schema instanceof AvroArray) {
      return _validateArray(schema, obj);
    } else if (schema instanceof Map) {
      return _validateMap(schema, obj);
    } else if (schema instanceof Primitive) {
      return _validatePrimitive(schema, obj);
    } else {
      throw new InvalidSchemaError('validation not yet implemented: ' + JSON.stringify(schema));
    }
  };

  var _validateRecord = function(schema, obj) {
    if (!_.isObject(obj) || _.isArray(obj)) {
      throw new ValidationError('Expected record Javascript type to be non-array object, got ' + JSON.stringify(obj));
    }

    var schemaFieldNames = _.pluck(schema.fields, 'name');
    var objFieldNames = _.keys(obj);
    if (!_.isEqual(schemaFieldNames, objFieldNames)) {
      throw new ValidationError('Expected record fields ' + JSON.stringify(schemaFieldNames) + '; got ' + JSON.stringify(objFieldNames));
    }

    return _.all(schema.fields, function(field) {
      return _validate(field.schema, obj[field.name]);
    });
  };

  var _validateUnion = function(schema, obj) {
    if (_.isObject(obj)) {
      if (_.isArray(obj)) {
        throw new ValidationError('Expected union Javascript type to be non-array object (or null), got ' + JSON.stringify(obj));
      } else if (_.size(obj) !== 1) {
        throw new ValidationError('Expected union Javascript object to be object with exactly 1 key (or null), got ' + JSON.stringify(obj));
      } else {
        var unionBranch = _.keys(obj)[0];
        if (unionBranch === "") {
          throw new ValidationError('Expected union Javascript object to contain non-empty string branch, got ' + JSON.stringify(obj));
        }
        if (_.contains(schema.branchNames(), unionBranch)) {
          return true;
        } else {
          throw new ValidationError('Expected union branch to be one of ' + JSON.stringify(schema.branchNames()) + '; got ' + JSON.stringify(unionBranch));
        }
      }
    } else if (_.isNull(obj)) {
      if (_.contains(schema.branchNames(), 'null')) {
        return true;
      } else {
        throw new ValidationError('Expected union branch to be one of ' + JSON.stringify(schema.branchNames()) + '; got ' + JSON.stringify(obj));
      }
    } else {
      throw new ValidationError('Expected union Javascript object to be non-array object of size 1 or null, got ' + JSON.stringify(obj));
    }
  };

  var _validateEnum = function(schema, obj) {
    if (_.isString(obj)) {
      if (_.contains(schema.symbols, obj)) {
        return true;
      } else {
        throw new ValidationError('Expected enum value to be one of ' + JSON.stringify(schema.symbols) + '; got ' + JSON.stringify(obj));
      }
    } else {
      throw new ValidationError('Expected enum Javascript object to be string, got ' + JSON.stringify(obj));
    }
  };

  var _validateArray = function(schema, obj) {
    if (_.isArray(obj)) {
      return _.all(obj, function(member) { return _validate(schema.itemSchema, member); });
    } else {
      throw new ValidationError('Expected array Javascript object to be array, got ' + JSON.stringify(obj));
    }
  };

  var _validateMap = function(schema, obj) {
    if (_.isObject(obj) && !_.isArray(obj)) {
      return _.all(obj, function(value) { return _validate(schema.valueSchema, value); });
    } else if (_.isArray(obj)) {
      throw new ValidationError('Expected map Javascript object to be non-array object, got array ' + JSON.stringify(obj));
    } else {
      throw new ValidationError('Expected map Javascript object to be non-array object, got ' + JSON.stringify(obj));
    }
  };

  var _validatePrimitive = function(schema, obj) {
    switch (schema.type) {
      case 'null':
        if (_.isNull(obj) || _.isUndefined(obj)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript null or undefined for Avro null, got ' + JSON.stringify(obj));
        }
        break;
      case 'boolean':
        if (_.isBoolean(obj)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript boolean for Avro boolean, got ' + JSON.stringify(obj));
        }
        break;
      case 'int':
        if (_.isNumber(obj) && Math.floor(obj) === obj && Math.abs(obj) <= Math.pow(2, 31)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript int32 number for Avro int, got ' + JSON.stringify(obj));
        }
        break;
      case 'long':
        if (_.isNumber(obj) && Math.floor(obj) === obj && Math.abs(obj) <= Math.pow(2, 63)) {
          return true;
        } else {
          throw new ValidationError('Expected Javascript int64 number for Avro long, got ' + JSON.stringify(obj));
        }
        break;
      case 'float':
        if (_.isNumber(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript float number for Avro float, got ' + JSON.stringify(obj));
        }
        break;
      case 'double':
        if (_.isNumber(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript double number for Avro double, got ' + JSON.stringify(obj));
        }
        break;
      case 'bytes':
        throw new InvalidSchemaError('not yet implemented: ' + schema.type);
      case 'string':
        if (_.isString(obj)) { // TODO: handle NaN?
          return true;
        } else {
          throw new ValidationError('Expected Javascript string for Avro string, got ' + JSON.stringify(obj));
        }
        break;
      default:
        throw new InvalidSchemaError('unrecognized primitive type: ' + schema.type);
    }
  };

  // TODO: namespace handling is rudimentary. multiple namespaces within a certain nested schema definition
  // are probably buggy.
  var _namedTypes = namedTypes || {};
  var _saveNamedType = function(fullyQualifiedTypeName, schema) {
    if (_.has(_namedTypes, fullyQualifiedTypeName)) {
      if (!_.isEqual(_namedTypes[fullyQualifiedTypeName], schema)) {
        throw new InvalidSchemaError('conflicting definitions for type ' + fullyQualifiedTypeName + ': ' + JSON.stringify(_namedTypes[fullyQualifiedTypeName]) + ' and ' + JSON.stringify(schema));
      }
    } else {
      _namedTypes[fullyQualifiedTypeName] = schema;
    }
  };

  var _lookupTypeByFullyQualifiedName = function(fullyQualifiedTypeName) {
    if (_.has(_namedTypes, fullyQualifiedTypeName)) {
      return _namedTypes[fullyQualifiedTypeName];
    } else {
      return null;
    }
  };

  var _parseNamedType = function(schema, namespace) {
    if (_.contains(AvroSpec.PrimitiveTypes, schema)) {
      return new Primitive(schema);
    } else if (!_.isNull(_lookupTypeByFullyQualifiedName(makeFullyQualifiedTypeName(schema, namespace)))) {
      return _lookupTypeByFullyQualifiedName(makeFullyQualifiedTypeName(schema, namespace));
    } else {
      throw new InvalidSchemaError('unknown type name: ' + JSON.stringify(schema) + '; known type names are ' + JSON.stringify(_.keys(_namedTypes)));
    }
  };

  var _parseSchema = function(schema, parentSchema, namespace) {
    if (_.isNull(schema) || _.isUndefined(schema)) {
      throw new InvalidSchemaError('schema is null, in parentSchema: ' + JSON.stringify(parentSchema));
    } else if (_.isString(schema)) {
      return _parseNamedType(schema, namespace);
    } else if (_.isObject(schema) && !_.isArray(schema)) {
      if (schema.type === 'record') {
        var newRecord = new Record(schema.name, schema.namespace, _.map(schema.fields, function(field) {
          return new Field(field.name, _parseSchema(field.type, schema, schema.namespace || namespace));
        }));
        _saveNamedType(makeFullyQualifiedTypeName(schema, namespace), newRecord);
        return newRecord;
      } else if (schema.type === 'enum') {
        if (_.has(schema, 'symbols')) {
          var newEnum = new Enum(schema.symbols);
          _saveNamedType(makeFullyQualifiedTypeName(schema, namespace), newEnum);
          return newEnum;
        } else {
          throw new InvalidSchemaError('enum must specify symbols, got ' + JSON.stringify(schema));
        }
      } else if (schema.type === 'array') {
        if (_.has(schema, 'items')) {
          return new AvroArray(_parseSchema(schema.items, schema, namespace));
        } else {
          throw new InvalidSchemaError('array must specify "items" schema, got ' + JSON.stringify(schema));
        }
      } else if (schema.type === 'map') {
        if (_.has(schema, 'values')) {
          return new Map(_parseSchema(schema.values, schema, namespace));
        } else {
          throw new InvalidSchemaError('map must specify "values" schema, got ' + JSON.stringify(schema));
        }
      } else if (_.has(schema, 'type') && _.contains(AvroSpec.PrimitiveTypes, schema.type)) {
        return _parseNamedType(schema.type, namespace);
      } else {
        throw new InvalidSchemaError('not yet implemented: ' + schema.type);
      }
    } else if (_.isArray(schema)) {
      if (_.isEmpty(schema)) {
        throw new InvalidSchemaError('unions must have at least 1 branch');
      }
      var branchTypes = _.map(schema, function(branchType) { return _parseSchema(branchType, schema, namespace); });
      return new Union(branchTypes, namespace);
    } else {
      throw new InvalidSchemaError('unexpected Javascript type for schema: ' + (typeof schema));
    }
  };

  this.rawSchema = schema;
  this.schema = _parseSchema(schema, namespace);
}

Validator.validate = function(schema, obj) {
  return (new Validator(schema)).validate(obj);
};

function ProtocolValidator(protocol) {
  this.validate = function(typeName, obj) {
    var fullyQualifiedTypeName = makeFullyQualifiedTypeName(typeName, protocol.namespace);
    if (!_.has(_typeSchemaValidators, fullyQualifiedTypeName)) {
      throw new ProtocolValidationError('Protocol does not contain definition for type ' + JSON.stringify(fullyQualifiedTypeName) + ' (fully qualified from input "' + typeName + '"); known types are ' + JSON.stringify(_.keys(_typeSchemaValidators)));
    }
    return _typeSchemaValidators[fullyQualifiedTypeName].validate(obj);
  };

  var _typeSchemaValidators = {};
  var _initSchemaValidators = function(protocol) {
    var namedTypes = {};
    if (!_.has(protocol, 'protocol') || !_.isString(protocol.protocol)) {
      throw new InvalidProtocolError('Protocol must contain a "protocol" attribute with a string value');
    }
    if (_.isArray(protocol.types)) {
      _.each(protocol.types, function(typeSchema) {
        var schemaValidator = new Validator(typeSchema, protocol.namespace, namedTypes);
        var fullyQualifiedTypeName = makeFullyQualifiedTypeName(typeSchema, protocol.namespace);
        _typeSchemaValidators[fullyQualifiedTypeName] = schemaValidator;
      });
    }
  };

  _initSchemaValidators(protocol);
}

ProtocolValidator.validate = function(protocol, typeName, obj) {
  return (new ProtocolValidator(protocol)).validate(typeName, obj);
};

if (typeof exports !== 'undefined') {
  exports['Validator'] = Validator;
  exports['ProtocolValidator'] = ProtocolValidator;
}
<|endoftext|>


<commit_before>var page = require("./mainpage.js").html();

module.exports = function (robot) {
    robot.router.get('/', function (req, res) {
        res.send(page)
    })

    robot.router.get("/a", function (request, response) {
 response.send(`
Token succesfuly received. You can now close the window.
\n
    				<button onclick=window.close()>close</button>`)

});
}<commit_msg>testing html<commit_after>var page = require("./mainpage.js").html();

module.exports = function (robot) {
    robot.router.get('/', function (req, res) {
        res.send(page)
    })

    robot.router.get("/a", function (request, response) {

        response.send(`

        `);
//  response.send(`
Token succesfuly received. You can now close the window.
\n
    				// <button onclick=window.close()>close</button>`)

});
}<|endoftext|>


<commit_before>/*
jQuery.ganttView v.0.7
Copyright (c) 2010 JC Grubbs - jc.grubbs@devmynd.com
MIT License Applies
*/

/*
Options
-----------------
showWeekends: boolean
data: object
start: date
end: date
cellWidth: number
cellHeight: number
slideWidth: number
*/

(function (jQuery) {
    jQuery.fn.ganttView = function (options) {

		var els = this;
		var defaults = {
			showWeekends: true,
			cellWidth: 21,
			cellHeight: 21,
			slideWidth: 400,
			vHeaderWidth: 100
		};
		var opts = jQuery.extend(defaults, options);
		var months = Gantt.getMonths(opts.start, opts.end);

		els.each(function () {

			var container = jQuery(this);
			var div = jQuery("<div>", { "class": "ganttview" });

			Gantt.addVtHeader(div, opts.data, opts.cellHeight);

			var slideDiv = jQuery("<div>", {
				"class": "ganttview-slide-container",
 				"css": { "width": opts.slideWidth + "px" }
			});

			Gantt.addHzHeader(slideDiv, months, opts.cellWidth);
			Gantt.addGrid(slideDiv, opts.data, months, opts.cellWidth, opts.showWeekends);
			Gantt.addBlockContainers(slideDiv, opts.data);
			Gantt.addBlocks(slideDiv, opts.data, opts.cellWidth, opts.start);

			div.append(slideDiv);
			container.append(div);

			var w = jQuery("div.ganttview-vtheader", container).outerWidth() +
				jQuery("div.ganttview-slide-container", container).outerWidth();
			container.css("width", (w + 2) + "px");

			Gantt.applyLastClass(container);
		});
	};

	var Gantt = {

		monthNames: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],

		getMonths: function (start, end) {
			var months = []; months[start.getMonth()] = [start];
			var last = start;
			while (last.compareTo(end) == -1) {
				var next = last.clone().addDays(1);
				if (!months[next.getMonth()]) { months[next.getMonth()] = []; }
				months[next.getMonth()].push(next);
				last = next;
			}
			return months;
		},

		addVtHeader: function (div, data, cellHeight) {
			var headerDiv = jQuery("<div>", { "class": "ganttview-vtheader" });
			for (var i = 0; i < data.length; i++) {
				var itemDiv = jQuery("<div>", { "class": "ganttview-vtheader-item" });
				itemDiv.append(jQuery("<div>", {
					"class": "ganttview-vtheader-item-name",
					"css": { "height": (data[i].series.length * cellHeight) + "px" }
				}).append(data[i].name));
				var seriesDiv = jQuery("<div>", { "class": "ganttview-vtheader-series" });
				for (var j = 0; j < data[i].series.length; j++) {
					seriesDiv.append(jQuery("<div>", { "class": "ganttview-vtheader-series-name" })
						.append(data[i].series[j].name));
				}
				itemDiv.append(seriesDiv);
				headerDiv.append(itemDiv);
			}
			div.append(headerDiv);
		},

		addHzHeader: function (div, months, cellWidth) {
			var headerDiv = jQuery("<div>", { "class": "ganttview-hzheader" });
			var monthsDiv = jQuery("<div>", { "class": "ganttview-hzheader-months" });
			var daysDiv = jQuery("<div>", { "class": "ganttview-hzheader-days" });
			var totalW = 0;
			for (var i = 0; i < 12; i++) {
				if (months[i]) {
					var w = months[i].length * cellWidth;
					totalW = totalW + w;
					monthsDiv.append(jQuery("<div>", {
						"class": "ganttview-hzheader-month",
						"css": { "width": (w - 1) + "px" }
					}).append(Gantt.monthNames[i]));
					for (var j = 0; j < months[i].length; j++) {
						daysDiv.append(jQuery("<div>", { "class": "ganttview-hzheader-day" })
							.append(months[i][j].getDate()));
					}
				}
			}
			monthsDiv.css("width", totalW + "px");
			daysDiv.css("width", totalW + "px");
			headerDiv.append(monthsDiv).append(daysDiv);
			div.append(headerDiv);
		},

		addGrid: function (div, data, months, cellWidth, showWeekends) {
			var gridDiv = jQuery("<div>", { "class": "ganttview-grid" });
			var rowDiv = jQuery("<div>", { "class": "ganttview-grid-row" });
			for (var i = 0; i < 12; i++) {
				if (months[i]) {
					for (var j = 0; j < months[i].length; j++) {
						var cellDiv = jQuery("<div>", { "class": "ganttview-grid-row-cell " });
						if (DateUtils.isWeekend(months[i][j]) && showWeekends) { cellDiv.addClass("ganttview-weekend"); }
						rowDiv.append(cellDiv);
					}
				}
			}
			var w = jQuery("div.ganttview-grid-row-cell", rowDiv).length * cellWidth;
			rowDiv.css("width", w + "px");
			gridDiv.css("width", w + "px");
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					gridDiv.append(rowDiv.clone());
				}
			}
			div.append(gridDiv);
		},

		addBlockContainers: function (div, data) {
			var blocksDiv = jQuery("<div>", { "class": "ganttview-blocks" });
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					blocksDiv.append(jQuery("<div>", { "class": "ganttview-block-container" }));
				}
			}
			div.append(blocksDiv);
		},

		addBlocks: function (div, data, cellWidth, start) {
			var rows = jQuery("div.ganttview-blocks div.ganttview-block-container", div);
			var rowIdx = 0;
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					var size = DateUtils.daysBetween(data[i].series[j].start, data[i].series[j].end);
					var offset = DateUtils.daysBetween(start, data[i].series[j].start);
					var blockDiv = jQuery("<div>", {
						"class": "ganttview-block",
						"title": data[i].series[j].name + ", " + size + " days",
						"css": {
							"width": ((size * cellWidth) - 9) + "px",
							"margin-left": ((offset * cellWidth) + 3) + "px"
						}
					});
					if (data[i].series[j].color) {
						blockDiv.css("background-color", data[i].series[j].color);
					}
					blockDiv.append($("<div>", { "class": "ganttview-block-text" }).text(size));
					jQuery(rows[rowIdx]).append(blockDiv);
					rowIdx = rowIdx + 1;
				}
			}
		},

		applyLastClass: function (div) {
			jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child", div).addClass("last");
			jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child", div).addClass("last");
			jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child", div).addClass("last");
		}

	};

	var ArrayUtils = {
		contains: function (arr, obj) {
			var has = false;
			for (var i = 0; i < arr.length; i++) { if (arr[i] == obj) { has = true; } }
			return has;
		}
	};

	var DateUtils = {
		daysBetween: function (start, end) {
			var count = 0, date = start.clone();
			while (date.compareTo(end) == -1) { count = count + 1; date.addDays(1); }
			return count;
		},
		isWeekend: function (date) {
			return date.getDay() % 6 == 0;
		}
	};

})(jQuery);<commit_msg>some internal refactoring and renaming<commit_after>/*
jQuery.ganttView v.0.7
Copyright (c) 2010 JC Grubbs - jc.grubbs@devmynd.com
MIT License Applies
*/

/*
Options
-----------------
showWeekends: boolean
data: object
start: date
end: date
cellWidth: number
cellHeight: number
slideWidth: number
*/

(function (jQuery) {
    jQuery.fn.ganttView = function (options) {

		var els = this;
		var defaults = {
			showWeekends: true,
			cellWidth: 21,
			cellHeight: 21,
			slideWidth: 400,
			vHeaderWidth: 100
		};
		var opts = jQuery.extend(defaults, options);
		var months = Chart.getMonths(opts.start, opts.end);

		els.each(function () {

			var container = jQuery(this);
			var div = jQuery("<div>", { "class": "ganttview" });

			Chart.addVtHeader(div, opts.data, opts.cellHeight);

			var slideDiv = jQuery("<div>", {
				"class": "ganttview-slide-container",
 				"css": { "width": opts.slideWidth + "px" }
			});

			Chart.addHzHeader(slideDiv, months, opts.cellWidth);
			Chart.addGrid(slideDiv, opts.data, months, opts.cellWidth, opts.showWeekends);
			Chart.addBlockContainers(slideDiv, opts.data);
			Chart.addBlocks(slideDiv, opts.data, opts.cellWidth, opts.start);

			div.append(slideDiv);
			container.append(div);

			var w = jQuery("div.ganttview-vtheader", container).outerWidth() +
				jQuery("div.ganttview-slide-container", container).outerWidth();
			container.css("width", (w + 2) + "px");

			Chart.applyLastClass(container);
		});
	};

	var Chart = {

		monthNames: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],

		getMonths: function (start, end) {
			var months = []; months[start.getMonth()] = [start];
			var last = start;
			while (last.compareTo(end) == -1) {
				var next = last.clone().addDays(1);
				if (!months[next.getMonth()]) { months[next.getMonth()] = []; }
				months[next.getMonth()].push(next);
				last = next;
			}
			return months;
		},

		addVtHeader: function (div, data, cellHeight) {
			var headerDiv = jQuery("<div>", { "class": "ganttview-vtheader" });
			for (var i = 0; i < data.length; i++) {
				var itemDiv = jQuery("<div>", { "class": "ganttview-vtheader-item" });
				itemDiv.append(jQuery("<div>", {
					"class": "ganttview-vtheader-item-name",
					"css": { "height": (data[i].series.length * cellHeight) + "px" }
				}).append(data[i].name));
				var seriesDiv = jQuery("<div>", { "class": "ganttview-vtheader-series" });
				for (var j = 0; j < data[i].series.length; j++) {
					seriesDiv.append(jQuery("<div>", { "class": "ganttview-vtheader-series-name" })
						.append(data[i].series[j].name));
				}
				itemDiv.append(seriesDiv);
				headerDiv.append(itemDiv);
			}
			div.append(headerDiv);
		},

		addHzHeader: function (div, months, cellWidth) {
			var headerDiv = jQuery("<div>", { "class": "ganttview-hzheader" });
			var monthsDiv = jQuery("<div>", { "class": "ganttview-hzheader-months" });
			var daysDiv = jQuery("<div>", { "class": "ganttview-hzheader-days" });
			var totalW = 0;
			for (var i = 0; i < 12; i++) {
				if (months[i]) {
					var w = months[i].length * cellWidth;
					totalW = totalW + w;
					monthsDiv.append(jQuery("<div>", {
						"class": "ganttview-hzheader-month",
						"css": { "width": (w - 1) + "px" }
					}).append(Chart.monthNames[i]));
					for (var j = 0; j < months[i].length; j++) {
						daysDiv.append(jQuery("<div>", { "class": "ganttview-hzheader-day" })
							.append(months[i][j].getDate()));
					}
				}
			}
			monthsDiv.css("width", totalW + "px");
			daysDiv.css("width", totalW + "px");
			headerDiv.append(monthsDiv).append(daysDiv);
			div.append(headerDiv);
		},

		addGrid: function (div, data, months, cellWidth, showWeekends) {
			var gridDiv = jQuery("<div>", { "class": "ganttview-grid" });
			var rowDiv = jQuery("<div>", { "class": "ganttview-grid-row" });
			for (var i = 0; i < 12; i++) {
				if (months[i]) {
					for (var j = 0; j < months[i].length; j++) {
						var cellDiv = jQuery("<div>", { "class": "ganttview-grid-row-cell " });
						if (DateUtils.isWeekend(months[i][j]) && showWeekends) { cellDiv.addClass("ganttview-weekend"); }
						rowDiv.append(cellDiv);
					}
				}
			}
			var w = jQuery("div.ganttview-grid-row-cell", rowDiv).length * cellWidth;
			rowDiv.css("width", w + "px");
			gridDiv.css("width", w + "px");
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					gridDiv.append(rowDiv.clone());
				}
			}
			div.append(gridDiv);
		},

		addBlockContainers: function (div, data) {
			var blocksDiv = jQuery("<div>", { "class": "ganttview-blocks" });
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					blocksDiv.append(jQuery("<div>", { "class": "ganttview-block-container" }));
				}
			}
			div.append(blocksDiv);
		},

		addBlocks: function (div, data, cellWidth, start) {
			var rows = jQuery("div.ganttview-blocks div.ganttview-block-container", div);
			var rowIdx = 0;
			for (var i = 0; i < data.length; i++) {
				for (var j = 0; j < data[i].series.length; j++) {
					var size = DateUtils.daysBetween(data[i].series[j].start, data[i].series[j].end);
					var offset = DateUtils.daysBetween(start, data[i].series[j].start);
					var blockDiv = jQuery("<div>", {
						"class": "ganttview-block",
						"title": data[i].series[j].name + ", " + size + " days",
						"css": {
							"width": ((size * cellWidth) - 9) + "px",
							"margin-left": ((offset * cellWidth) + 3) + "px"
						}
					});
					if (data[i].series[j].color) {
						blockDiv.css("background-color", data[i].series[j].color);
					}
					blockDiv.append($("<div>", { "class": "ganttview-block-text" }).text(size));
					jQuery(rows[rowIdx]).append(blockDiv);
					rowIdx = rowIdx + 1;
				}
			}
		},

		applyLastClass: function (div) {
			jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child", div).addClass("last");
			jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child", div).addClass("last");
			jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child", div).addClass("last");
		}

	};

	var ArrayUtils = {
		contains: function (arr, obj) {
			var has = false;
			for (var i = 0; i < arr.length; i++) { if (arr[i] == obj) { has = true; } }
			return has;
		}
	};

	var DateUtils = {
		daysBetween: function (start, end) {
			var count = 0, date = start.clone();
			while (date.compareTo(end) == -1) { count = count + 1; date.addDays(1); }
			return count;
		},
		isWeekend: function (date) {
			return date.getDay() % 6 == 0;
		}
	};

})(jQuery);<|endoftext|>


<commit_before>'use strict';

const utils = require( './utils' );

const AlternativesValidator = require( './alternatives' );

function handleSuccess( values, validated, options, callback ) {

    if( callback ) {

        callback( null, validated );
        return;
    }

    if( options.updateValues === true ) {

        Object.keys( validated ).forEach( function( key ) {

            values[ key ] = validated[ key ];
        });
    }

    let value;

    if( options.valueIsWrapped ) {

        // extract validated value
        value = validated.value;
    }
    else {

        value = Object.assign( {}, values, validated );
    }

    return { error: null, value };
}

function handleError( values, error, options, callback ) {

    if( callback ) {

        callback( error );
    }

    return { error, value: values };
}

function validateAgaintUnvalidatedKeys( value, schema ) {

    let unvalidated = [];

    Object.keys( value ).forEach( function( key ) {

        if( !schema[ key ] ) {

            unvalidated.push( key );
        }
    });

    if( unvalidated.length > 0 ) {

        let message;

        switch( unvalidated.length ) {

            case 1:
                message = '"' + unvalidated[0] + '"' + ' is not allowed';
                break;

            case 2:
                message =  '"' + unvalidated[0] + '" and "' + unvalidated[1] + '" are not allowed';
                break;

            default:
                message = '"' + unvalidated[0] + '"';

                let last = unvalidated.length - 1;

                for( let i = 1; i < unvalidated.length; i++ ) {

                    message+= ', ';

                    if( i === last ) {

                        message+= 'and ';
                    }

                    message+= '"' + unvalidated[i] + '"'
                }

                message+= ' are not allowed';
        }

        throw new Error( message );
    }
}

function validator( values, schema /*, options, callback*/ ) {

    // we might modify the options
    let options = {};

    let callback;

    if( arguments.length === 3 ) {

        if( utils.isFunction( arguments[2] ) ) {

            callback = arguments[ 2 ];
        }
        else {

            options = Object.assign( options, arguments[ 2 ] );
        }
    }
    else if( arguments.length >= 4 ) {

        options = Object.assign( options, arguments[ 2 ] );

        callback = arguments[ 3 ];
    }

    let validated = {};

    // handle case where user is using short form ([]) for alternatives
    if( Array.isArray( schema ) ) {

        schema = new AlternativesValidator().try( schema );
    }

    let originalValues = values;

    if( utils.isFunction( schema.validate ) ) {

        // single value/validator case

        values = { value: values };
        schema = { value: schema };

        options.valueIsWrapped = true;
    }
    else {

        values = values || {};
    }

    let keys = Object.keys( schema );

    if( options.allowAdditional !== true ) {

        try {

            validateAgaintUnvalidatedKeys( values, schema, options, callback );
        }
        catch( err ) {

            return handleError( originalValues, err, options, callback );
        }
    }

    for( let i = 0; i < keys.length; i++ ) {

        let key = keys[i];

        let keyValidator = schema[ key ];

        if( Array.isArray( keyValidator ) ) {

            keyValidator = new AlternativesValidator().try( keyValidator );
        }

        let value = values[ key ];

        try {

            validated[ key ]  = keyValidator.validate( value );
        }
        catch( err ) {

            let error = new Error( key + ': ' + err.message );

            error.cause = err;

            return handleError( originalValues, error, options, callback );
        }
    }

    return handleSuccess( originalValues, validated, options, callback );
}

module.exports = validator;
<commit_msg>removed cause from error - information was redundant<commit_after>'use strict';

const utils = require( './utils' );

const AlternativesValidator = require( './alternatives' );

function handleSuccess( values, validated, options, callback ) {

    if( callback ) {

        callback( null, validated );
        return;
    }

    if( options.updateValues === true ) {

        Object.keys( validated ).forEach( function( key ) {

            values[ key ] = validated[ key ];
        });
    }

    let value;

    if( options.valueIsWrapped ) {

        // extract validated value
        value = validated.value;
    }
    else {

        value = Object.assign( {}, values, validated );
    }

    return { error: null, value };
}

function handleError( values, error, options, callback ) {

    if( callback ) {

        callback( error );
    }

    return { error, value: values };
}

function validateAgaintUnvalidatedKeys( value, schema ) {

    let unvalidated = [];

    Object.keys( value ).forEach( function( key ) {

        if( !schema[ key ] ) {

            unvalidated.push( key );
        }
    });

    if( unvalidated.length > 0 ) {

        let message;

        switch( unvalidated.length ) {

            case 1:
                message = '"' + unvalidated[0] + '"' + ' is not allowed';
                break;

            case 2:
                message =  '"' + unvalidated[0] + '" and "' + unvalidated[1] + '" are not allowed';
                break;

            default:
                message = '"' + unvalidated[0] + '"';

                let last = unvalidated.length - 1;

                for( let i = 1; i < unvalidated.length; i++ ) {

                    message+= ', ';

                    if( i === last ) {

                        message+= 'and ';
                    }

                    message+= '"' + unvalidated[i] + '"'
                }

                message+= ' are not allowed';
        }

        throw new Error( message );
    }
}

function validator( values, schema /*, options, callback*/ ) {

    // we might modify the options
    let options = {};

    let callback;

    if( arguments.length === 3 ) {

        if( utils.isFunction( arguments[2] ) ) {

            callback = arguments[ 2 ];
        }
        else {

            options = Object.assign( options, arguments[ 2 ] );
        }
    }
    else if( arguments.length >= 4 ) {

        options = Object.assign( options, arguments[ 2 ] );

        callback = arguments[ 3 ];
    }

    let validated = {};

    // handle case where user is using short form ([]) for alternatives
    if( Array.isArray( schema ) ) {

        schema = new AlternativesValidator().try( schema );
    }

    let originalValues = values;

    if( utils.isFunction( schema.validate ) ) {

        // single value/validator case

        values = { value: values };
        schema = { value: schema };

        options.valueIsWrapped = true;
    }
    else {

        values = values || {};
    }

    let keys = Object.keys( schema );

    if( options.allowAdditional !== true ) {

        try {

            validateAgaintUnvalidatedKeys( values, schema, options, callback );
        }
        catch( err ) {

            return handleError( originalValues, err, options, callback );
        }
    }

    for( let i = 0; i < keys.length; i++ ) {

        let key = keys[i];

        let keyValidator = schema[ key ];

        if( Array.isArray( keyValidator ) ) {

            keyValidator = new AlternativesValidator().try( keyValidator );
        }

        let value = values[ key ];

        try {

            validated[ key ]  = keyValidator.validate( value );
        }
        catch( err ) {

            let error = new Error( key + ': ' + err.message );

            return handleError( originalValues, error, options, callback );
        }
    }

    return handleSuccess( originalValues, validated, options, callback );
}

module.exports = validator;
<|endoftext|>


<commit_before>import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';
import config from './config/environment';
import getAndInitNewEpisodes from "./lib/getAndInitNewEpisodes"

var App;
var ipc = nRequire("ipc");
Ember.MODEL_FACTORY_INJECTIONS = true;

var notifier = nRequire('node-notifier');
var episodesToString = function(episodes){
  var episode = episodes[0];
  if(episodes.length == 1) {
    return episode.get("show")  + " " + episode.get("what") +
      " was released";
  }

  return episode.get("show")  + " " + episode.get("what") + " and " +
    (episodes.length - 1) + " others";
}

Ember.Application.initializer({
  name: "fetchLoop",
  initialize: function(container, application) {
    var checkForEp = function(){
      var store = container.lookup("store:main");
      var epController = container.lookup('controller:episodes');
      getAndInitNewEpisodes(store, function(episodes) {
        episodes.forEach(function(episode) {
          epController.get("episodes").unshiftObject(episode);
          episode.loading();
        });

        if(episodes.length > 0){
          notifier.notify({
            'title': 'New episodes',
            'message': episodesToString(episodes)
          });

          ipc.sendSync('newBackgroundEpisodes', 1);
        }
      });
    }
    setInterval(checkForEp, 1 * 60 * 60 * 1000);
    checkForEp();
  }
});

import User from "./lib/user";

Ember.Application.initializer({
  name: "initUser",
  initialize: function(container, app) {
    app.register('service:user', User, { instantiate: true, singleton: true });
    app.inject('controller', 'currentUser', "service:user");
    app.inject('route', 'currentUser', "service:user");
  }
});

App = Ember.Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver: Resolver
});

loadInitializers(App, config.modulePrefix);

export default App;<commit_msg>Fix init loading<commit_after>import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';
import config from './config/environment';
import getAndInitNewEpisodes from "./lib/getAndInitNewEpisodes"

var App;
var ipc = nRequire("ipc");
Ember.MODEL_FACTORY_INJECTIONS = true;

var notifier = nRequire('node-notifier');
var episodesToString = function(episodes){
  var episode = episodes[0];
  if(episodes.length == 1) {
    return episode.get("show")  + " " + episode.get("what") +
      " was released";
  }

  return episode.get("show")  + " " + episode.get("what") + " and " +
    (episodes.length - 1) + " others";
}

Ember.Application.initializer({
  name: "fetchLoop",
  initialize: function(container, application) {
    var checkForEp = function(){
      var store = container.lookup("store:main");
      var epController = container.lookup('controller:episodes');
      getAndInitNewEpisodes(epController.currentUser, store).then(function(episodes) {
        episodes.forEach(function(episode) {
          epController.get("episodes").unshiftObject(episode);
          episode.loading();
        });

        if(episodes.length > 0){
          notifier.notify({
            'title': 'New episodes',
            'message': episodesToString(episodes)
          });

          ipc.sendSync("newBackgroundEpisodes", 1);
        }
      });
    }
    setInterval(checkForEp, 1 * 60 * 60 * 1000);
    checkForEp();
  }
});

import User from "./lib/user";

Ember.Application.initializer({
  name: "initUser",
  initialize: function(container, app) {
    app.register('service:user', User, { instantiate: true, singleton: true });
    app.inject('controller', 'currentUser', "service:user");
    app.inject('route', 'currentUser', "service:user");
  }
});

App = Ember.Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver: Resolver
});

loadInitializers(App, config.modulePrefix);

export default App;<|endoftext|>


<commit_before>(function( $ ) {

	var methods = {
		isEventOnIcon : function( e ) {

			var $this = $(this),

				data = $this.data( 'iconfield' ),
				left = data['left'],

				// calculate the x and y relative to the text field
				x = e.pageX - $this.position().left,
				y = e.pageY - $this.position().top,

				// get dimensions from options
				x_padding = $this.iconfield( 'option', 'horizontal-padding' ),
				y_padding = $this.iconfield( 'option', 'vertical-padding' ),
				image_width = $this.iconfield( 'option', 'image-width' ),
				image_height = $this.iconfield( 'option', 'image-height' );

				// calculate the offset of the left side of the icon
				x_offset = left ? x_padding : $this.width() - x_padding - image_width;

			return (
				( x >= x_offset && x <= ( x_offset + image_width ) )
				&&
				( y >= y_padding && y <= ( y_padding + image_height ) )
			);

		},

		refresh : function( ) {

			return this.each( function( ) {
				var $this = $(this),
					data = $this.data( 'iconfield' ),
					image = new Image();

				// about to load the image so we can find out what the image's dimensions are

				image.onload = function( ) {

					var left = data['left'],
						x_padding = data['horizontal-padding'],
						y_padding = data['vertical-padding'],
						bg_position = left ?
									  x_padding :
									  $this.width() - ( x_padding * 2 );

					var style_map = {
						'background-image': 'url(' + data['image-url'] + ')',
						'background-repeat': 'no-repeat',
						'background-position': bg_position + 'px center',
					};

					if ( left ) {
						style_map['padding-left'] = image.width + (x_padding * 2);
					}
					else {
						$.extend( style_map, {
							'padding-left': x_padding,
							'padding-right': (x_padding * 2) + image.width,
						} );
					}

					if ( data['old-cursor'] ) {
						style_map['cursor'] = data['old-cursor'];
					}

					// calculate the minimal height this textfield should take,
					// taking into account the image's height and paddings beneath and above it
					var minimal_height = image.height + y_padding * 2;
					var current_height = Number($this.css( 'height' ).slice(0, -2))

					// add padding if the field's current height is not high enough to include the image
					// (+ vertical padding)
					if ( current_height < minimal_height ) {
						// the padding is the difference between the minimal height and the current height
						// divided by two, because one half goes to the bottom and one to the top
						var padding = (minimal_height - current_height) / 2;
						$.extend( style_map, {
							'padding-top': padding,
							'padding-bottom' : padding,
						} );
					}

					// add image dimensions to the data stored for this element
					$.extend( data, {
						'image-width': image.width,
						'image-height': image.height,
					} );

					// update the field's style
					$this.css( style_map );
				}

				image.src = data['image-url'];

			} );

		},

		init : function( options ) {

			return this.each( function( ) {

				var $this = $(this);

				// initialize the element's iconfield data with the defaults
				$this.data( 'iconfield', new Object() );
				$this.iconfield( 'option', $.extend( {
					'horizontal-padding': 2,
					'vertical-padding': 4,
					'icon-cursor': 'auto',
					'left': true,
				}, options ) );

				// create a custom event that is triggered when the icon is clicked
				$this.on( 'click', function( e ) {
					if ( $this.iconfield( 'isEventOnIcon', e ) ) {
						$this.trigger( 'iconfield.click' );
					}
				} );

				// bind to mousemove for simulating mouseenter and mouseleave events
				$this.on( 'mousemove', function( e ) {
					var data = $this.data( 'iconfield' ),
						was_on_icon = data['was-on-icon'] === undefined || data['was-on-icon'],
						cur_on_icon = $this.iconfield( 'isEventOnIcon', e );

					// this is obvious
					$this.trigger( 'iconfield.mousemove' );

					// if the mouse is on the icon and wasn't before, or vice versa,
					// trigger the relevant event and store the current state of
					// the mouse
					if ( cur_on_icon != was_on_icon ) {
						if ( cur_on_icon && !was_on_icon ) {
							$this.trigger( 'iconfield.mouseenter' );
						}
						else if ( !cur_on_icon && was_on_icon ) {
							$this.trigger( 'iconfield.mouseleave' );
						}

						data['was-on-icon'] = cur_on_icon;
					}
				} );

				// bind to our simulated mouseenter event to change the cursor
				// when the mouse is hovering over the icon
				$this.on( 'iconfield.mouseenter', function( e ) {
					var data = $this.data( 'iconfield' ),
						cur_cursor = $this.css( 'cursor' );

					// 'auto' means that no special cursor was specified by the user
					if( data['icon-cursor'] != 'auto' &&
						data['icon-cursor'] != cur_cursor) {
						// save the cursor before it's changed
						data['old-cursor'] = cur_cursor ? cur_cursor : 'auto';

						// change the cursor
						$this.css( 'cursor', data['icon-cursor'] );
					}
				} );

				// change the icon back to normal
				$this.on( 'iconfield.mouseleave', function( e ) {
					var data = $this.data( 'iconfield' );

					// 'auto' means that no special cursor was specified by the user,
					// meaning that there is nothing to change back to
					if( data['icon-cursor'] != 'auto' ) {
						// if no old cursor was stored (meaning that the mouse was never on the icon)
						// change back to 'auto'
						$this.css( 'cursor', data['old-cursor'] ? data['old-cursor'] : 'auto' );
					}
				} );

				// refresh the styling
				$this.iconfield( 'refresh' );

			} );

		},

		option : function( name, value ) {

			return $.access( this, function( elem, name, value ) {
				var $this = $(elem),
					data = $this.data('iconfield');

				if ( value !== undefined ) {
					data[name] = value;
				} else {
					return data[name];
				}
			}, name, value, arguments.length > 1 );

		}
	}

	$.fn.iconfield = function( method ) {

		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		}
		else {
			$.error( 'Method ' + method + ' does not exist on jQuery.iconfield' );
		}
	}

})(jQuery);<commit_msg>fixed another underscore.js dependancy, some cleanup and coding-style conformity fixes<commit_after>(function( $ ) {

	var methods = {
		isEventOnIcon : function( e ) {

			var $this = $(this),

				data = $this.data( 'iconfield' ),
				left = data['left'],

				// calculate the x and y relative to the text field
				x = e.pageX - $this.position().left,
				y = e.pageY - $this.position().top,

				// get dimensions from options
				x_padding = $this.iconfield( 'option', 'horizontal-padding' ),
				y_padding = $this.iconfield( 'option', 'vertical-padding' ),
				image_width = $this.iconfield( 'option', 'image-width' ),
				image_height = $this.iconfield( 'option', 'image-height' );

				// calculate the offset of the left side of the icon
				x_offset = left ? x_padding : $this.width() - x_padding - image_width;

			return (
				( x >= x_offset && x <= ( x_offset + image_width ) )
				&&
				( y >= y_padding && y <= ( y_padding + image_height ) )
			);

		},

		refresh : function( ) {

			return this.each( function( ) {
				var $this = $(this),
					data = $this.data( 'iconfield' ),
					image = new Image();

				// about to load the image so we can find out what the image's dimensions are

				image.onload = function( ) {

					var left = data['left'],
						x_padding = data['horizontal-padding'],
						y_padding = data['vertical-padding'],
						bg_position = left ?
									  x_padding :
									  $this.width() - ( x_padding * 2 );

					var style_map = {
						'background-image': 'url(' + data['image-url'] + ')',
						'background-repeat': 'no-repeat',
						'background-position': bg_position + 'px center',
					};

					if ( left ) {
						style_map['padding-left'] = image.width + ( x_padding * 2 );
					}
					else {
						$.extend( style_map, {
							'padding-left': x_padding,
							'padding-right': ( x_padding * 2 ) + image.width,
						} );
					}

					if ( data['old-cursor'] ) {
						style_map['cursor'] = data['old-cursor'];
					}

					// calculate the minimal height this textfield should take,
					// taking into account the image's height and paddings beneath and above it
					var minimal_height = image.height + ( y_padding * 2 );
					var current_height = Number( $this.css( 'height' ).slice( 0, -2 ) )

					// add padding if the field's current height is not high enough to include the image
					// (+ vertical padding)
					if ( current_height < minimal_height ) {
						// the padding is the difference between the minimal height and the current height
						// divided by two, because one half goes to the bottom and one to the top
						var padding = ( minimal_height - current_height ) / 2;
						$.extend( style_map, {
							'padding-top': padding,
							'padding-bottom' : padding,
						} );
					}

					// add image dimensions to the data stored for this element
					$.extend( data, {
						'image-width': image.width,
						'image-height': image.height,
					} );

					// update the field's style
					$this.css( style_map );
				}

				image.src = data['image-url'];

			} );

		},

		init : function( options ) {

			return this.each( function( ) {

				var $this = $(this);

				// initialize the element's iconfield data with the defaults
				$this.data( 'iconfield', new Object() );
				$this.iconfield( 'option', $.extend( {
					'horizontal-padding': 2,
					'vertical-padding': 4,
					'icon-cursor': 'auto',
					'left': true,
				}, options ) );

				// create a custom event that is triggered when the icon is clicked
				$this.on( 'click', function( e ) {
					if ( $this.iconfield( 'isEventOnIcon', e ) ) {
						$this.trigger( 'iconfield.click' );
					}
				} );

				// bind to mousemove for simulating mouseenter and mouseleave events
				$this.on( 'mousemove', function( e ) {
					var data = $this.data( 'iconfield' ),
						was_on_icon = data['was-on-icon'] === undefined || data['was-on-icon'],
						cur_on_icon = $this.iconfield( 'isEventOnIcon', e );

					// this is obvious
					$this.trigger( 'iconfield.mousemove' );

					// if the mouse is on the icon and wasn't before, or vice versa,
					// trigger the relevant event and store the current state of
					// the mouse
					if ( cur_on_icon != was_on_icon ) {
						if ( cur_on_icon && !was_on_icon ) {
							$this.trigger( 'iconfield.mouseenter' );
						}
						else if ( !cur_on_icon && was_on_icon ) {
							$this.trigger( 'iconfield.mouseleave' );
						}

						data['was-on-icon'] = cur_on_icon;
					}
				} );

				// bind to our simulated mouseenter event to change the cursor
				// when the mouse is hovering over the icon
				$this.on( 'iconfield.mouseenter', function( e ) {
					var data = $this.data( 'iconfield' ),
						cur_cursor = $this.css( 'cursor' );

					// 'auto' means that no special cursor was specified by the user
					if( data['icon-cursor'] != 'auto' &&
						data['icon-cursor'] != cur_cursor) {
						// save the cursor before it's changed
						data['old-cursor'] = cur_cursor ? cur_cursor : 'auto';

						// change the cursor
						$this.css( 'cursor', data['icon-cursor'] );
					}
				} );

				// change the icon back to normal
				$this.on( 'iconfield.mouseleave', function( e ) {
					var data = $this.data( 'iconfield' );

					// 'auto' means that no special cursor was specified by the user,
					// meaning that there is nothing to change back to
					if( data['icon-cursor'] != 'auto' ) {
						// if no old cursor was stored (meaning that the mouse was never on the icon)
						// change back to 'auto'
						$this.css( 'cursor', data['old-cursor'] ? data['old-cursor'] : 'auto' );
					}
				} );

				// refresh the styling
				$this.iconfield( 'refresh' );

			} );

		},

		option : function( name, value ) {

			return $.access( this, function( elem, name, value ) {
				var $this = $(elem),
					data = $this.data('iconfield');

				if ( value !== undefined ) {
					data[name] = value;
				} else {
					return data[name];
				}
			}, name, value, arguments.length > 1 );

		}
	}

	$.fn.iconfield = function( method ) {

		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		}
		else {
			$.error( 'Method ' + method + ' does not exist on jQuery.iconfield' );
		}
	}

})(jQuery);<|endoftext|>


<commit_before>'use strict';

var mockery = require('mockery');
var S = require('string');
var path = require('path');

describe('route_init', function () {
	var RouteInitializer;
	var mockFileMgr;
	var mockApp;

	var config;
	var testObject;

	// List of files that the file manager shows as existing.
	var filesThatExist;

	//
	// Mocks that have been registered before or during a test and should be
	// unregistered after.
	//
	var registeredMocks = [];

	//
	// Register a require mock, the mock will be unregistered automatically
	// after the test.
	//
	var registerRequireMock = function (mockName, mock) {

		//console.log('Mocking: ' + mockName);

		mockery.registerMock(mockName, mock);

		registeredMocks.push(mockName);
	};

	//
	// Unregister all require mocks that have been registered to this point.
	//
	var unregisterRequireMocks = function () {

		registeredMocks.forEach(function (mockName) {
			mockery.deregisterMock(mockName);
		});

		registeredMocks = [];
	};

	beforeEach(function () {
		registeredMocks = [];

		mockery.enable();

		filesThatExist = [];

		mockFileMgr = {
			fileExists: function (filePath) {
				for (var i = 0; i < filesThatExist.length; ++i) {
					if (filePath == filesThatExist[i]) {
						return true;
					}
				}
				return false;
			},

			getDirectories: function (dir) {
				return [];
			},

		};

		mockApp = {
			get: jasmine.createSpy(),
		};

		registerRequireMock('./fileMgr', mockFileMgr);
		mockery.registerAllowable('./route_init');
		mockery.registerAllowable('path');

		RouteInitializer = require('./route_init');

		config = {};
		testObject = new RouteInitializer(config, mockApp);
	});

	afterEach(function () {
		mockery.deregisterAllowable('./route_init');
		mockery.deregisterAllowable('path');
		unregisterRequireMocks();

		mockery.disable();
	});

	// Helper: Create a directory to pass into route init.
	var initDir = function (childDirName, parentPath, parent) {
		parentPath = parentPath || "";
		if (arguments.length < 3) {
			parent = {
				config: {},
			};
		}

		return {
			name: childDirName,
			path: path.join(parentPath, childDirName),
			parentRoute: '/' + parentPath,
			config: {},
			parent: parent,
		};
	};

	// Helper: Create a mock user-get-config.
	var initMockGetConfig = function (path) {
		filesThatExist.push(path);

		var mockGetConfig = {
			handler: jasmine.createSpy(),
		};

		registerRequireMock(testObject._formatPathForRequire(path), mockGetConfig);

		return mockGetConfig;
	};

	it('directory with get.js registers for HTTP get', function () {

		var parentDirName = 'parent';
		var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('directory without get.js does not register for HTTP get', function () {

		var parentDirName = 'parent';
		var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

		testObject._processDirectory(dir);

		expect(mockApp.get).not.toHaveBeenCalled();
	});

	it('when get.js exists, it is loaded to handle a route', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockGetConfig.handler).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('sub-directory with get.js registers for HTTP get', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('when get.js exists in a sub-directory, it is loaded to handle a route', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockGetConfig.handler).toHaveBeenCalledWith(mockReq, mockRes)
	});

    it('directory with route.js can customize its route', function () {

        var parentDirName = 'parent';
        var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

        var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        filesThatExist.push(dirConfigPath);

        var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

        var customizedRouteName = 'customized-route';
        var mockDirConfig = {
        	route: customizedRouteName,
        };
        registerRequireMock(testObject._formatPathForRequire(dirConfigPath), mockDirConfig);

        testObject._processDirectory(dir);

        var expectedRoutePath = '/' + parentDirName + '/' + customizedRouteName;
        expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
    });

    it('directory with route.js doesnt customize its route when it is not specified', function () {

        var parentDirName = 'parent';
        var childDirName = 'child';
        var dir = initDir(childDirName, parentDirName);

        var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        filesThatExist.push(dirConfigPath);

        var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

        var mockDirConfig = {};
        registerRequireMock(testObject._formatPathForRequire(dirConfigPath), mockDirConfig);

        testObject._processDirectory(dir);

        var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
        expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
    });

	it('name of root directory doesnt appear in route path', function () {

		var rootDirName = 'root';
        var dir = initDir(rootDirName, "", null);

		var getConfigPath = path.join(rootDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/';
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('route path can be customized', function () {

		var rootDirName = 'root';
        var dir = initDir(rootDirName, "", null);

		var dirConfigPath = path.join(rootDirName, 'route.js');
        filesThatExist.push(dirConfigPath);

		var getConfigPath = path.join(rootDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		var customizedRoute = 'customized';
        var mockDirConfig = {
        	route: customizedRoute
        };
        registerRequireMock(testObject._formatPathForRequire(dirConfigPath), mockDirConfig);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + customizedRoute;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('route is opened', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName);

		var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        filesThatExist.push(dirConfigPath);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		var mockDirConfig = {
			openRoute: jasmine.createSpy(),
		};

		registerRequireMock(testObject._formatPathForRequire(dirConfigPath), mockDirConfig);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockDirConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('parent route is opened when a child route is handled', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var childGetConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var parentDirConfigPath = path.join(parentDirName, 'route.js');
        filesThatExist.push(parentDirConfigPath);

		var mockGetConfig = initMockGetConfig(childGetConfigPath);

		var mockDirConfig = {
			openRoute: jasmine.createSpy(),
		};
		registerRequireMock(testObject._formatPathForRequire(parentDirConfigPath), mockDirConfig);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockDirConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('fully mocked parent is opened when a child route is handled', function () {

		var dirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(dirName, parentDirName, {
			config: {
					userConfig: {
						openRoute: jasmine.createSpy(),
					},
				},
		});

		var getConfigPath = path.join(parentDirName, dirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(dir.parent.config.userConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('parent of parent is opened when a route is handled', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName, {
			config: {
					userConfig: {
						openRoute: jasmine.createSpy(),
					},
				},
		});

		var childGetConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(childGetConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(dir.parent.config.userConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

});<commit_msg>Simplified tests.<commit_after>'use strict';

var mockery = require('mockery');
var S = require('string');
var path = require('path');

describe('route_init', function () {
	var RouteInitializer;
	var mockFileMgr;
	var mockApp;

	var config;
	var testObject;

	// List of files that the file manager shows as existing.
	var filesThatExist;

	//
	// Mocks that have been registered before or during a test and should be
	// unregistered after.
	//
	var registeredMocks = [];

	//
	// Register a require mock, the mock will be unregistered automatically
	// after the test.
	//
	var registerRequireMock = function (mockName, mock) {

		//console.log('Mocking: ' + mockName);

		mockery.registerMock(mockName, mock);

		registeredMocks.push(mockName);
	};

	//
	// Unregister all require mocks that have been registered to this point.
	//
	var unregisterRequireMocks = function () {

		registeredMocks.forEach(function (mockName) {
			mockery.deregisterMock(mockName);
		});

		registeredMocks = [];
	};

	beforeEach(function () {
		registeredMocks = [];

		mockery.enable();

		filesThatExist = [];

		mockFileMgr = {
			fileExists: function (filePath) {
				for (var i = 0; i < filesThatExist.length; ++i) {
					if (filePath == filesThatExist[i]) {
						return true;
					}
				}
				return false;
			},

			getDirectories: function (dir) {
				return [];
			},

		};

		mockApp = {
			get: jasmine.createSpy(),
		};

		registerRequireMock('./fileMgr', mockFileMgr);
		mockery.registerAllowable('./route_init');
		mockery.registerAllowable('path');

		RouteInitializer = require('./route_init');

		config = {};
		testObject = new RouteInitializer(config, mockApp);
	});

	afterEach(function () {
		mockery.deregisterAllowable('./route_init');
		mockery.deregisterAllowable('path');
		unregisterRequireMocks();

		mockery.disable();
	});

	// Helper: Create a directory to pass into route init.
	var initDir = function (childDirName, parentPath, parent) {
		parentPath = parentPath || "";
		if (arguments.length < 3) {
			parent = {
				config: {},
			};
		}

		return {
			name: childDirName,
			path: path.join(parentPath, childDirName),
			parentRoute: '/' + parentPath,
			config: {},
			parent: parent,
		};
	};

	// Helper: Create a mock user-get-config.
	var initMockGetConfig = function (path) {
		filesThatExist.push(path);

		var mockGetConfig = {
			handler: jasmine.createSpy(),
		};

		registerRequireMock(testObject._formatPathForRequire(path), mockGetConfig);

		return mockGetConfig;
	};

	// Helper: Create a mock user-dir-config.
	var initMockDirConfig = function (path) {
		var mockDirConfig = {
			openRoute: jasmine.createSpy(),
		};
		registerRequireMock(testObject._formatPathForRequire(path), mockDirConfig);

		filesThatExist.push(path);

		return mockDirConfig;
	};

	it('directory with get.js registers for HTTP get', function () {

		var parentDirName = 'parent';
		var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('directory without get.js does not register for HTTP get', function () {

		var parentDirName = 'parent';
		var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

		testObject._processDirectory(dir);

		expect(mockApp.get).not.toHaveBeenCalled();
	});

	it('when get.js exists, it is loaded to handle a route', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockGetConfig.handler).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('sub-directory with get.js registers for HTTP get', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('when get.js exists in a sub-directory, it is loaded to handle a route', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockGetConfig.handler).toHaveBeenCalledWith(mockReq, mockRes)
	});

    it('directory with route.js can customize its route', function () {

        var parentDirName = 'parent';
        var childDirName = 'child';
		var dir = initDir(childDirName, parentDirName);

        var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

        var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        var mockDirConfig = initMockDirConfig(dirConfigPath);

        var customizedRouteName = 'customized-route';
        mockDirConfig.route = customizedRouteName;

        testObject._processDirectory(dir);

        var expectedRoutePath = '/' + parentDirName + '/' + customizedRouteName;
        expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
    });

    it('directory with route.js doesnt customize its route when it is not specified', function () {

        var parentDirName = 'parent';
        var childDirName = 'child';
        var dir = initDir(childDirName, parentDirName);

        var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

        var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        var mockDirConfig = initMockDirConfig(dirConfigPath);

        testObject._processDirectory(dir);

        var expectedRoutePath = '/' + parentDirName + '/' + childDirName;
        expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
    });

	it('name of root directory doesnt appear in route path', function () {

		var rootDirName = 'root';
        var dir = initDir(rootDirName, "", null);

		var getConfigPath = path.join(rootDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var expectedRoutePath = '/';
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('route path can be customized', function () {

		var rootDirName = 'root';
        var dir = initDir(rootDirName, "", null);

		var getConfigPath = path.join(rootDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		var dirConfigPath = path.join(rootDirName, 'route.js');
        var mockDirConfig = initMockDirConfig(dirConfigPath);

		var customizedRoute = 'customized';
        mockDirConfig.route = customizedRoute;

		testObject._processDirectory(dir);

		var expectedRoutePath = '/' + customizedRoute;
		expect(mockApp.get).toHaveBeenCalledWith(expectedRoutePath, jasmine.any(Function));
	});

	it('route is opened', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName);

		var getConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		var dirConfigPath = path.join(parentDirName, childDirName, 'route.js');
        var mockDirConfig = initMockDirConfig(dirConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockDirConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('parent route is opened when a child route is handled', function () {

		var parentDirName = 'parent';
		var dir = initDir(parentDirName);

		var childDirName = 'child';
		mockFileMgr.getDirectories = function (dirPath) {
			if (dirPath === parentDirName) {
				return [ childDirName ];
			}
			else {
				return [];
			}
		};

		var childGetConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(childGetConfigPath);

		var parentDirConfigPath = path.join(parentDirName, 'route.js');
        var mockDirConfig = initMockDirConfig(parentDirConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(mockDirConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('fully mocked parent is opened when a child route is handled', function () {

		var dirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(dirName, parentDirName, {
			config: {
					userConfig: {
						openRoute: jasmine.createSpy(),
					},
				},
		});

		var getConfigPath = path.join(parentDirName, dirName, 'get.js');
		var mockGetConfig = initMockGetConfig(getConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(dir.parent.config.userConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

	it('parent of parent is opened when a route is handled', function () {

		var childDirName = 'child';
		var parentDirName = 'parent';
		var dir = initDir(childDirName, parentDirName, {
			config: {
					userConfig: {
						openRoute: jasmine.createSpy(),
					},
				},
		});

		var childGetConfigPath = path.join(parentDirName, childDirName, 'get.js');
		var mockGetConfig = initMockGetConfig(childGetConfigPath);

		testObject._processDirectory(dir);

		var handler = mockApp.get.mostRecentCall.args[1];

		// Simulate a request.
		var mockReq = {};
		var mockRes = {};
		handler(mockReq, mockRes);

		expect(dir.parent.config.userConfig.openRoute).toHaveBeenCalledWith(mockReq, mockRes)
	});

});<|endoftext|>