<commit_before>'use strict';

const debug = require('debug')('koa-spec');
const _ = require('lodash');
const path = require('path');
const HTTPStatus = require('http-status');
const utils = require('./utils');
const parseBoolean = utils.parseBoolean;
const errors = require('./errors');

const RouterError = errors.RouterError;

const RouteError = errors.RouteError;
const RouteNotImplementedError = errors.RouteNotImplementedError;

const ParameterValidationError = errors.ParameterValidationError;

const SourceValidationError = errors.SourceValidationError;
const RequiredValidationError = errors.RequiredValidationError;
const TypeValidationError = errors.TypeValidationError;
const FormatValidationError = errors.FormatValidationError;

const CONTROLLER_DIRECTORY_DEFAULT = './controllers';
const STRICT_MODE_DEFAULT = true;

const INTEGER_INT32_MAX_VALUE = 2147483647;
const INTEGER_INT32_MIN_VALUE = -2147483648;
const INTEGER_INT64_MAX_VALUE = Number.MAX_SAFE_INTEGER;
const INTEGER_INT64_MIN_VALUE = Number.MIN_SAFE_INTEGER;
const NUMBER_FLOAT_MIN_VALUE = -3.4028235E38;
const NUMBER_FLOAT_MAX_VALUE = 3.4028235E38;

module.exports = function (uri, options) {
  const refOptions = (options && options.refOptions) ? options.refOptions : undefined;
  const spec = utils.readSpec(uri, refOptions);

  const routerOptions = (options && options.routerOptions) ? options.routerOptions : undefined;
  const router = createRouter(spec, routerOptions);

  return {
    spec   : spec.resolved,
    refs   : spec.refs,
    router : router
  }
};

function createRouter(spec, options) {
  function getControllerMethod(controllerDirectory, controllerName, controllerMethodName, strictMode, method, route) {
    if (!controllerName) {
      throw new RouteError(method, route, `Controller name not specified. Specify via 'x-controller'.`);
    }

    const controllerPath = path.join(controllerDirectory, controllerName);
    if (!utils.isRequireResolvable(controllerPath)) {
      if (strictMode) {
        throw new RouteError(method, route, `Controller '${controllerName}' does not exist.`);
      }
    } else {
      if (!controllerMethodName) {
        throw new RouteError(method, route, `Controller '${controllerName}' method name not specified. Specify via 'x-controller-method'.`);
      }
      const controller = require(controllerPath);
      const controllerMethod = controller[controllerMethodName];
      if (controllerMethod) {
        return controllerMethod;
      }
      if (strictMode) {
        throw new RouteError(method, route, `Controller '${controllerName}' does not have a method '${controllerMethodName}'.`);
      }
    }

    /* Fallback */
    return createNotImplementedControllerMethod(method, route);
  }

  function createNotImplementedControllerMethod(method, route) {
    return function* (next) {
      this.status = HTTPStatus.NOT_IMPLEMENTED;
      const err = new RouteNotImplementedError(method, route);
      this.body = {
        code    : err.code,
        message : err.message,
        route   : {
          method : method,
          path   : route
        }
      };
    }
  }

  return function () {
    const koarouter = require('koa-router');
    if (!koarouter) {
      throw new RouterError(`Module 'koa-router' isn't available. Install via 'npm install --save koa-router'.`)
    }
    const router = koarouter();

    const controllerDirectory = (options && !_.isUndefined(options.controllerDirectory)) ? options.controllerDirectory : CONTROLLER_DIRECTORY_DEFAULT;
    const strictMode = (options && !_.isUndefined(options.strictMode)) ? options.strictMode : STRICT_MODE_DEFAULT;

    if (!utils.isDirectory(controllerDirectory)) {
      throw new RouterError(`Controller directory '${controllerDirectory}' does not exist.`);
    }

    const routes = spec.resolved.paths;
    _.forOwn(routes, function (methods, route) {

      /* Convert from spec to router parameter syntax: */
      route = route.replace(/{[^/]*}/g, function replacer(match) {
        /* Cut first and last character, prepend with colon: */
        return ':' + match.slice(1, -1);
      });

      _.forOwn(methods, function (methodInfo, method) {
        const controllerName = methodInfo['x-controller'];
        const controllerMethodName = methodInfo['x-controller-method'];

        const controllerMethod = getControllerMethod(controllerDirectory, controllerName, controllerMethodName, strictMode, method, route);

        if (router[method]) {
          // Check if any of the parameters of this method uses a body parameter:
          const bodyParameter = _.find(methodInfo.parameters, {in : 'body'});
          if (bodyParameter) {
            // Make sure the koa-bodyparser is available:
            if (!require('koa-bodyparser')) {
              throw new RouteError(method, route, `Detected 'body' parameter: '${bodyParameter.name}' but module 'koa-bodyparser' isn't available. Install via 'npm install --save koa-bodyparser'.`)
            }
          }
          const requestValidator = createRequestValidator(spec, method, route, methodInfo.parameters);
          router[method](route, requestValidator, controllerMethod);
        } else {
          throw new RouteError(method, route, `Method '${method}' does not exist.`);
        }
      });
    });

    return router;
  }
}

function createRequestValidator(spec, method, route, parameterDefinitions) {
  function validateBoolean(name, type, format, value) {
    const actualValue = parseBoolean(value);

    if (!_.isBoolean(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'boolean'.`);
    }

    return actualValue;
  }

  function validateInteger(name, type, format, value) {
    const actualValue = parseInt(value, 10);

    if (isNaN(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not an 'integer'.`);
    } else if (parseFloat(value) % 1 !== 0) { // Checks if this actually was a float, not an integer!
      throw new TypeValidationError(name, type, format, value, `Not an 'integer'.`);
    }

    switch (format) {
      case 'int32':
        return validateIntegerInt32(name, type, format, value, actualValue);
      case 'int64':
        return validateIntegerInt64(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateIntegerInt32(name, type, format, value, actualValue) {
    if (actualValue > INTEGER_INT32_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum integer (int32) value: ${INTEGER_INT32_MAX_VALUE}.`);
    } else if (actualValue < INTEGER_INT32_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum integer (int32) value: ${INTEGER_INT32_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateIntegerInt64(name, type, format, value, actualValue) {
    if (actualValue > INTEGER_INT64_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum integer (int64) value: ${INTEGER_INT64_MAX_VALUE}.`);
    } else if (actualValue < INTEGER_INT64_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum integer (int64) value: ${INTEGER_INT64_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateNumber(name, type, format, value) {
    const actualValue = parseFloat(value);
    if (isNaN(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'number'.`);
    }

    switch (format) {
      case 'float':
        return validateNumberFloat(name, type, format, value, actualValue);
      case 'double':
        return validateNumberDouble(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateNumberFloat(name, type, format, value, actualValue) {
    if (actualValue > NUMBER_FLOAT_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum number (float) value: ${NUMBER_FLOAT_MAX_VALUE}.`);
    } else if (actualValue < NUMBER_FLOAT_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum number (float) value: ${NUMBER_FLOAT_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateNumberDouble(name, type, format, value, actualValue) {
    return actualValue;
  }

  function validateString(name, type, format, value) {
    const actualValue = value;
    if (!_.isString(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'string'.`);
    }

    switch (format) {
      case undefined:
        // No specified format means a simple string. Nothing to check for here.
        return actualValue;
      case 'uuid':
        return validateStringUUID(name, type, format, value, actualValue);
      case 'isbn':
        return validateStringISBN(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateStringUUID(name, type, format, value, actualValue) {
    if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) {
      throw new FormatValidationError(name, type, format, value, `Not a 'uuid'.`);
    }
    return actualValue;
  }

  function validateStringISBN(name, type, format, value, actualValue) {
    if (!/^(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$/i.test(value)) {
      throw new FormatValidationError(name, type, format, value, `Not a 'isbn'.`);
    }
    return actualValue;
  }

  function validateArray(name, type, format, items, values) {
    if (!_.isArray(values)) {
      throw new TypeValidationError(name, type, format, values, `Not an 'array'.`);
    }
    if (!items) {
      throw new TypeValidationError(name, type, format, values, `Items not found.`);
    }

    return _.map(values, value => {
      return validateProperties(name, type, format, items.properties, items.required, value);
    });
  }

  function validateProperties(name, type, format, properties, required, value) {
    const actualValue = {};
    if (!properties) {
      throw new TypeValidationError(name, type, format, value, `Properties not found.`);
    }

    _.forOwn(properties, (propertyInfo, propertyName) => {
      const refName = propertyInfo['$ref'];
      const propertyValue = value[propertyName];

      if (refName) {
        const ref = spec.refs[`${refName}/properties/${propertyName}`];
        propertyInfo = _.get(spec.resolved, utils.pathFromPtr(ref.uri).join('.'));
      }

      /* Check for required properties: */
      if (_.includes(required, propertyName)) {
        if (_.isUndefined(propertyValue)) {
          throw new RequiredValidationError(propertyName, propertyInfo.type, propertyInfo.format, undefined, '');
        }
      } else {
        if (_.isUndefined(propertyValue)) {
          return;
        }
      }

      const validatedPropertyValue = validateValue(propertyName, propertyInfo.type, propertyInfo.format, propertyInfo.items, propertyInfo.properties, propertyInfo.required, propertyValue);
      actualValue[propertyName] = validatedPropertyValue;
    });
    return actualValue;
  }

  function validateValue(name, type, format, items, properties, required, value) {
    switch (type) {
      case 'boolean':
        return validateBoolean(name, type, format, value);
      case 'integer':
        return validateInteger(name, type, format, value);
      case 'number':
        return validateNumber(name, type, format, value);
      case 'string':
        return validateString(name, type, format, value);
      case 'object':
        return validateProperties(name, type, format, properties, required, value);
      case 'array':
        return validateArray(name, type, format, items, value);
      default:
        throw new TypeValidationError(name, type, format, value, `Unsupported type: '${type}'.`);
    }
  }

  function validateSchema(name, type, format, schema, value) {
    if (!schema) {
      throw new TypeValidationError(name, type, format, value, `Schema not found.`);
    }

    switch (schema.type) {
      case 'object':
        return validateProperties(name, type, format, schema.properties, schema.required, value);
      case 'array':
        return validateArray(name, type, format, schema.items, value);
      default:
        throw new TypeValidationError(name, type, format, value, `Unsupported schema type: '${schema.type}'.`);
    }
  }

  function validateParameter(parameterDefinition, parameterValue) {
    try {
      if (parameterDefinition.required) {
        if (_.isUndefined(parameterValue)) {
          throw new RequiredValidationError(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, undefined, '');
        }
      } else {
        if (_.isUndefined(parameterValue)) {
          return parameterValue;
        }
      }

      if (parameterDefinition.in === 'body') {
        return validateSchema(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, parameterDefinition.schema, parameterValue);
      } else {
        return validateValue(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, parameterDefinition.items, undefined, undefined, parameterValue);
      }
    } catch (err) {
      throw new ParameterValidationError(parameterDefinition, parameterValue, err);
    }
  }

  function getParameterValue(ctx, parameterDefinition) {
    const parameterSource = getRequestParameterSource(ctx, parameterDefinition);
    switch (parameterDefinition.in) {
      case 'body':
        return parameterSource;
      default:
        return parameterSource[parameterDefinition.name];
    }
  }

  function setParameterValue(ctx, parameterDefinition, validatedParameterValue) {
    if (parameterDefinition.in === 'body') {
      ctx.request.body = validatedParameterValue;
    } else {
      const parameterSource = getRequestParameterSource(ctx, parameterDefinition);
      parameterSource[parameterDefinition.name] = validatedParameterValue;
    }
  }

  function getRequestParameterSource(ctx, parameterDefinition) {
    switch (parameterDefinition.in) {
      case 'path':
        return ctx.params;
      case 'query':
        return ctx.query;
      case 'body':
        return ctx.request.body;
      default:
        throw new ParameterValidationError(parameterDefinition, undefined, new SourceValidationError(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, undefined, `Unknown source: '${parameterDefinition.in}'.`));
    }
  }

  return function* validateRequest(next) {
    try {
      _.forEach(parameterDefinitions, parameterDefinition => {
        const parameterValue = getParameterValue(this, parameterDefinition);
        const validatedParameterValue = validateParameter(parameterDefinition, parameterValue);
        setParameterValue(this, parameterDefinition, validatedParameterValue);
      }, []);

      yield next;
    } catch (err) {
      debug(err);

      this.status = HTTPStatus.BAD_REQUEST;
      this.body = {
        code      : err.code,
        message   : err.message,
        route     : {
          method : method,
          path   : route
        },
        parameter : {
          expected : err.parameterDefinition,
          actual   : err.parameterValue
        }
      }
    }
  };
}<commit_msg>:lipstick: Minor changes.<commit_after>'use strict';

const debug = require('debug')('koa-spec');
const _ = require('lodash');
const path = require('path');
const HTTPStatus = require('http-status');
const utils = require('./utils');
const parseBoolean = utils.parseBoolean;
const errors = require('./errors');

const RouterError = errors.RouterError;

const RouteError = errors.RouteError;
const RouteNotImplementedError = errors.RouteNotImplementedError;

const ParameterValidationError = errors.ParameterValidationError;

const SourceValidationError = errors.SourceValidationError;
const RequiredValidationError = errors.RequiredValidationError;
const TypeValidationError = errors.TypeValidationError;
const FormatValidationError = errors.FormatValidationError;

const CONTROLLER_DIRECTORY_DEFAULT = './controllers';
const STRICT_MODE_DEFAULT = true;

const INTEGER_INT32_MAX_VALUE = 2147483647;
const INTEGER_INT32_MIN_VALUE = -2147483648;
const INTEGER_INT64_MAX_VALUE = Number.MAX_SAFE_INTEGER;
const INTEGER_INT64_MIN_VALUE = Number.MIN_SAFE_INTEGER;
const NUMBER_FLOAT_MIN_VALUE = -3.4028235E38;
const NUMBER_FLOAT_MAX_VALUE = 3.4028235E38;

module.exports = function (uri, options) {
  const refOptions = (options && options.refOptions) ? options.refOptions : undefined;
  const spec = utils.readSpec(uri, refOptions);

  const routerOptions = (options && options.routerOptions) ? options.routerOptions : undefined;
  const router = createRouter(spec, routerOptions);

  return {
    spec   : spec.resolved,
    refs   : spec.refs,
    router : router
  }
};

function createRouter(spec, options) {
  function getControllerMethod(controllerDirectory, controllerName, controllerMethodName, strictMode, method, route) {
    if (!controllerName) {
      throw new RouteError(method, route, `Controller name not specified. Specify via 'x-controller'.`);
    }

    const controllerPath = path.join(controllerDirectory, controllerName);
    if (!utils.isRequireResolvable(controllerPath)) {
      if (strictMode) {
        throw new RouteError(method, route, `Controller '${controllerName}' does not exist.`);
      }
    } else {
      if (!controllerMethodName) {
        throw new RouteError(method, route, `Controller '${controllerName}' method name not specified. Specify via 'x-controller-method'.`);
      }
      const controller = require(controllerPath);
      const controllerMethod = controller[controllerMethodName];
      if (controllerMethod) {
        return controllerMethod;
      }
      if (strictMode) {
        throw new RouteError(method, route, `Controller '${controllerName}' does not have a method '${controllerMethodName}'.`);
      }
    }

    /* Fallback */
    return createNotImplementedControllerMethod(method, route);
  }

  function createNotImplementedControllerMethod(method, route) {
    return function* (next) {
      this.status = HTTPStatus.NOT_IMPLEMENTED;
      const err = new RouteNotImplementedError(method, route);
      this.body = {
        code    : err.code,
        message : err.message,
        route   : {
          method : method,
          path   : route
        }
      };
    }
  }

  return function () {
    const koarouter = require('koa-router');
    if (!koarouter) {
      throw new RouterError(`Module 'koa-router' isn't available. Install via 'npm install --save koa-router'.`)
    }
    const router = koarouter();

    const controllerDirectory = (options && !_.isUndefined(options.controllerDirectory)) ? options.controllerDirectory : CONTROLLER_DIRECTORY_DEFAULT;
    const strictMode = (options && !_.isUndefined(options.strictMode)) ? options.strictMode : STRICT_MODE_DEFAULT;

    if (!utils.isDirectory(controllerDirectory)) {
      throw new RouterError(`Controller directory '${controllerDirectory}' does not exist.`);
    }

    const routes = spec.resolved.paths;
    _.forOwn(routes, function (methods, route) {

      /* Convert from spec to router parameter syntax: */
      route = route.replace(/{[^/]*}/g, function replacer(match) {
        /* Cut first and last character, prepend with colon: */
        return ':' + match.slice(1, -1);
      });

      _.forOwn(methods, function (methodInfo, method) {
        const controllerName = methodInfo['x-controller'];
        const controllerMethodName = methodInfo['x-controller-method'];

        const controllerMethod = getControllerMethod(controllerDirectory, controllerName, controllerMethodName, strictMode, method, route);

        if (router[method]) {
          // Check if any of the parameters of this method uses a body parameter:
          const bodyParameter = _.find(methodInfo.parameters, {in : 'body'});
          if (bodyParameter) {
            // Make sure the koa-bodyparser is available:
            if (!require('koa-bodyparser')) {
              throw new RouteError(method, route, `Detected 'body' parameter: '${bodyParameter.name}' but module 'koa-bodyparser' isn't available. Install via 'npm install --save koa-bodyparser'.`)
            }
          }
          const requestValidator = createRequestValidator(spec, method, route, methodInfo.parameters);
          router[method](route, requestValidator, controllerMethod);
        } else {
          throw new RouteError(method, route, `Method '${method}' does not exist.`);
        }
      });
    });

    return router;
  }
}

function createRequestValidator(spec, method, route, parameterDefinitions) {
  function validateBoolean(name, type, format, value) {
    const actualValue = parseBoolean(value);

    if (!_.isBoolean(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'boolean'.`);
    }

    return actualValue;
  }

  function validateInteger(name, type, format, value) {
    const actualValue = parseInt(value, 10);

    if (isNaN(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not an 'integer'.`);
    } else if (parseFloat(value) % 1 !== 0) { // Checks if this actually was a float, not an integer!
      throw new TypeValidationError(name, type, format, value, `Not an 'integer'.`);
    }

    switch (format) {
      case 'int32':
        return validateIntegerInt32(name, type, format, value, actualValue);
      case 'int64':
        return validateIntegerInt64(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateIntegerInt32(name, type, format, value, actualValue) {
    if (actualValue > INTEGER_INT32_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum integer (int32) value: ${INTEGER_INT32_MAX_VALUE}.`);
    } else if (actualValue < INTEGER_INT32_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum integer (int32) value: ${INTEGER_INT32_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateIntegerInt64(name, type, format, value, actualValue) {
    if (actualValue > INTEGER_INT64_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum integer (int64) value: ${INTEGER_INT64_MAX_VALUE}.`);
    } else if (actualValue < INTEGER_INT64_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum integer (int64) value: ${INTEGER_INT64_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateNumber(name, type, format, value) {
    const actualValue = parseFloat(value);
    if (isNaN(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'number'.`);
    }

    switch (format) {
      case 'float':
        return validateNumberFloat(name, type, format, value, actualValue);
      case 'double':
        return validateNumberDouble(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateNumberFloat(name, type, format, value, actualValue) {
    if (actualValue > NUMBER_FLOAT_MAX_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Maximum number (float) value: ${NUMBER_FLOAT_MAX_VALUE}.`);
    } else if (actualValue < NUMBER_FLOAT_MIN_VALUE) {
      throw new FormatValidationError(name, type, format, value, `Minimum number (float) value: ${NUMBER_FLOAT_MIN_VALUE}.`);
    }
    return actualValue;
  }

  function validateNumberDouble(name, type, format, value, actualValue) {
    return actualValue;
  }

  function validateString(name, type, format, value) {
    const actualValue = value;
    if (!_.isString(actualValue)) {
      throw new TypeValidationError(name, type, format, value, `Not a 'string'.`);
    }

    switch (format) {
      case undefined:
        // No specified format means a simple string. Nothing to check for here.
        return actualValue;
      case 'uuid':
        return validateStringUUID(name, type, format, value, actualValue);
      case 'isbn':
        return validateStringISBN(name, type, format, value, actualValue);
      default:
        throw new FormatValidationError(name, type, format, value, `Unknown format: ${format}.`);
    }
  }

  function validateStringUUID(name, type, format, value, actualValue) {
    if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) {
      throw new FormatValidationError(name, type, format, value, `Not a 'uuid'.`);
    }
    return actualValue;
  }

  function validateStringISBN(name, type, format, value, actualValue) {
    if (!/^(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$/i.test(value)) {
      throw new FormatValidationError(name, type, format, value, `Not a 'isbn'.`);
    }
    return actualValue;
  }

  function validateArray(name, type, format, items, values) {
    if (!_.isArray(values)) {
      throw new TypeValidationError(name, type, format, values, `Not an 'array'.`);
    }
    if (!items) {
      throw new TypeValidationError(name, type, format, values, `Items not found.`);
    }

    return _.map(values, value => {
      return validateProperties(name, type, format, items.properties, items.required, value);
    });
  }

  function validateProperties(name, type, format, properties, required, value) {
    const actualValue = {};
    if (!properties) {
      throw new TypeValidationError(name, type, format, value, `Properties not found.`);
    }

    _.forOwn(properties, (propertyInfo, propertyName) => {
      const refName = propertyInfo['$ref'];
      if (refName) {
        const ref = spec.refs[`${refName}/properties/${propertyName}`];
        propertyInfo = _.get(spec.resolved, utils.pathFromPtr(ref.uri).join('.'));
      }

      const propertyValue = value[propertyName];
      /* Check for required properties: */
      if (_.includes(required, propertyName)) {
        if (_.isUndefined(propertyValue)) {
          throw new RequiredValidationError(propertyName, propertyInfo.type, propertyInfo.format, undefined, '');
        }
      } else {
        if (_.isUndefined(propertyValue)) {
          return;
        }
      }

      const validatedPropertyValue = validateValue(propertyName, propertyInfo.type, propertyInfo.format, propertyInfo.items, propertyInfo.properties, propertyInfo.required, propertyValue);
      actualValue[propertyName] = validatedPropertyValue;
    });
    return actualValue;
  }

  function validateValue(name, type, format, items, properties, required, value) {
    switch (type) {
      case 'boolean':
        return validateBoolean(name, type, format, value);
      case 'integer':
        return validateInteger(name, type, format, value);
      case 'number':
        return validateNumber(name, type, format, value);
      case 'string':
        return validateString(name, type, format, value);
      case 'object':
        return validateProperties(name, type, format, properties, required, value);
      case 'array':
        return validateArray(name, type, format, items, value);
      default:
        throw new TypeValidationError(name, type, format, value, `Unsupported type: '${type}'.`);
    }
  }

  function validateSchema(name, type, format, schema, value) {
    if (!schema) {
      throw new TypeValidationError(name, type, format, value, `Schema not found.`);
    }

    switch (schema.type) {
      case 'object':
        return validateProperties(name, type, format, schema.properties, schema.required, value);
      case 'array':
        return validateArray(name, type, format, schema.items, value);
      default:
        throw new TypeValidationError(name, type, format, value, `Unsupported schema type: '${schema.type}'.`);
    }
  }

  function validateParameter(parameterDefinition, parameterValue) {
    try {
      if (parameterDefinition.required) {
        if (_.isUndefined(parameterValue)) {
          throw new RequiredValidationError(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, undefined, '');
        }
      } else {
        if (_.isUndefined(parameterValue)) {
          return parameterValue;
        }
      }

      if (parameterDefinition.in === 'body') {
        return validateSchema(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, parameterDefinition.schema, parameterValue);
      } else {
        return validateValue(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, parameterDefinition.items, undefined, undefined, parameterValue);
      }
    } catch (err) {
      throw new ParameterValidationError(parameterDefinition, parameterValue, err);
    }
  }

  function getParameterValue(ctx, parameterDefinition) {
    const parameterSource = getRequestParameterSource(ctx, parameterDefinition);
    switch (parameterDefinition.in) {
      case 'body':
        return parameterSource;
      default:
        return parameterSource[parameterDefinition.name];
    }
  }

  function setParameterValue(ctx, parameterDefinition, validatedParameterValue) {
    if (parameterDefinition.in === 'body') {
      ctx.request.body = validatedParameterValue;
    } else {
      const parameterSource = getRequestParameterSource(ctx, parameterDefinition);
      parameterSource[parameterDefinition.name] = validatedParameterValue;
    }
  }

  function getRequestParameterSource(ctx, parameterDefinition) {
    switch (parameterDefinition.in) {
      case 'path':
        return ctx.params;
      case 'query':
        return ctx.query;
      case 'body':
        return ctx.request.body;
      default:
        throw new ParameterValidationError(parameterDefinition, undefined, new SourceValidationError(parameterDefinition.name, parameterDefinition.type, parameterDefinition.format, undefined, `Unknown source: '${parameterDefinition.in}'.`));
    }
  }

  return function* validateRequest(next) {
    try {
      _.forEach(parameterDefinitions, parameterDefinition => {
        const parameterValue = getParameterValue(this, parameterDefinition);
        const validatedParameterValue = validateParameter(parameterDefinition, parameterValue);
        setParameterValue(this, parameterDefinition, validatedParameterValue);
      }, []);

      yield next;
    } catch (err) {
      debug(err);

      this.status = HTTPStatus.BAD_REQUEST;
      this.body = {
        code      : err.code,
        message   : err.message,
        route     : {
          method : method,
          path   : route
        },
        parameter : {
          expected : err.parameterDefinition,
          actual   : err.parameterValue
        }
      }
    }
  };
}<|endoftext|>


<commit_before>//FIX fix difference between wsdl parsed by json-q and by old parser

//TODO make it works with browsers (IE9+) => json-q.min.js, size?
//TODO AMD support?
//TODO add strings? (and remove _replace_escaped_operators)
//TODO performance?

const clone = require('clone');
const { dedup, deep_filter, flatten } = require('./helper');
const { parse } = require('./parse');
const { parse_filter } = require('./parse_filter');
const { operator } = require('./filter_operators');
const { pseudo } = require('./filter_pseudos');

const get = (obj, path, opt) => {
	const ret = _get(clone(obj), parse(path), opt);
	return ret;
}

const _get = (obj, flow, opt) => {
	flow = Object.assign([], flow);
	let ret = [];
	if (obj instanceof Array) {
		obj.forEach(_itm => {
			ret = ret.concat(_get(_itm, flow, opt));
		})
	} else {
		ret = [obj];
		while (flow[0]) {
			if (flow[0].any) {
				ret = _find_field(ret, flow[0].any, true); //deep find_field
			} else
			if (flow[0].next) {
				ret = _find_field(ret, flow[0].next);
			} else {
				ret = []
			}
			if (flow[0].transformation) {
				flow[0].transformation.forEach(_transformation => {
					let filtered_ret = ret;
					if (_transformation.filter) {
						filtered_ret = []
						ret.forEach(_itm => {
							let o = _obj_filter(_itm, _transformation.filter, opt);
							if (o) filtered_ret = filtered_ret.concat(o);
						})
					}
					if (_transformation.pseudo) {
						filtered_ret = _obj_pseudo(ret, _transformation.pseudo, opt);
					}
					ret = filtered_ret;
				})
			}
			flow.splice(0, 1);
		}
	}

	ret = dedup(ret); //dedup as "a b c" at {a:{b:{b:{c:{z:1}}}}} can return [{z:1}, {z:1}]
	return ret;
}

const _find_field = (obj, fieldName, deep) => {
	let ret = [];
	if (obj) {
		if (obj instanceof Array) {
			obj.forEach(_itm => {
				ret = ret.concat(_find_field(_itm, fieldName, deep));
			})
		} else {
			if (fieldName==='*') {
				if (typeof obj == 'object') {
					if (deep) ret.push(obj); // ".*" does not include current level (while " *" does)
					for (let i in obj) {
						ret.push(obj[i]);
						if (deep) ret = ret.concat(_find_field(obj[i], fieldName, true));
					}
				} else {
					ret.push(obj);
				}
			} else {
				if (obj[fieldName]) {
					if (obj[fieldName] instanceof Array) {
						ret = ret.concat(flatten(obj[fieldName]));
					} else {
						ret.push(flatten(obj[fieldName]));
					}
				}
				if (deep && typeof obj == 'object') {
					for (let i in obj)
						ret = ret.concat(_find_field(obj[i], fieldName, true));
				}
			}
		}
	}
	return ret;
}

const _obj_pseudo = (obj, pseudoName, opt) => {
	let localPseudo = Object.assign({}, pseudo, (opt || {}).pseudo);

	const func = localPseudo[pseudoName] || function(){return obj};
	return func(obj);
}

//remove items of multiple values (i.e. from arrays) that does not satisfies filter (at any level of nested of object)
const _obj_filter = (obj, filter, opt) => {
	const filterParsed = parse_filter(filter, opt);

	if (!filterParsed.left) {
		return obj;
	}

	if (!_obj_satisfies_filter(obj, filterParsed, opt)) {
		return;
	} else {
		return deep_filter(obj, (_itm, parent, parent_key) => {
			if (_itm instanceof Array) {
				let filtered = [];
				if (!parent) {
					for (let i=0; i<_itm.length; i++) {
						if (_obj_satisfies_filter(_itm[i], filterParsed, opt)) filtered.push(_itm[i]);
					}
				} else {
					//by the way, parent[parent_key] == _itm, _itm is array
					let saved = parent[parent_key];

					const parent_backup = (parent instanceof Array ? [] : {});
					const parent_keys = Object.keys(parent);
					for (let j in parent) {
						parent_backup[j] = parent[j];
						parent[j] = undefined;
					}

					for (let i=0; i<saved.length; i++) {
						parent[parent_key] = [saved[i]];
						if (_obj_satisfies_filter(obj, filterParsed, opt)) {
							filtered.push(saved[i]);
						}
					}

					for (let j in parent_backup) {
						parent[j] = parent_backup[j];
					}
					parent[parent_key] = filtered;
				}
				_itm = filtered;
			}
			return _itm
		});
	}
}

//is 'obj' satisfies 'filter' condition
//(filter can be like this "a.b.c=d", that means obj.a.b.c = d)
//(if obj.a.b.c returns array (look at _get) then it returns true if it contains filter value)
const _obj_satisfies_filter = (obj, filterParsed, opt) => {
	let localOperator = Object.assign({}, operator, (opt || {}).operator);

	const complexField = filterParsed.left;
	const value = filterParsed.right;
	const equal = localOperator[filterParsed.delimiter] || function(){};

	let complexFieldValue = _get(obj, parse(complexField), opt);

	return equal(complexFieldValue, value);
}

module.exports = { get };
<commit_msg>fix TODOs<commit_after>const clone = require('clone');
const { dedup, deep_filter, flatten } = require('./helper');
const { parse } = require('./parse');
const { parse_filter } = require('./parse_filter');
const { operator } = require('./filter_operators');
const { pseudo } = require('./filter_pseudos');

const get = (obj, path, opt) => {
	const ret = _get(clone(obj), parse(path), opt);
	return ret;
}

const _get = (obj, flow, opt) => {
	flow = Object.assign([], flow);
	let ret = [];
	if (obj instanceof Array) {
		obj.forEach(_itm => {
			ret = ret.concat(_get(_itm, flow, opt));
		})
	} else {
		ret = [obj];
		while (flow[0]) {
			if (flow[0].any) {
				ret = _find_field(ret, flow[0].any, true); //deep find_field
			} else
			if (flow[0].next) {
				ret = _find_field(ret, flow[0].next);
			} else {
				ret = []
			}
			if (flow[0].transformation) {
				flow[0].transformation.forEach(_transformation => {
					let filtered_ret = ret;
					if (_transformation.filter) {
						filtered_ret = []
						ret.forEach(_itm => {
							let o = _obj_filter(_itm, _transformation.filter, opt);
							if (o) filtered_ret = filtered_ret.concat(o);
						})
					}
					if (_transformation.pseudo) {
						filtered_ret = _obj_pseudo(ret, _transformation.pseudo, opt);
					}
					ret = filtered_ret;
				})
			}
			flow.splice(0, 1);
		}
	}

	ret = dedup(ret); //dedup as "a b c" at {a:{b:{b:{c:{z:1}}}}} can return [{z:1}, {z:1}]
	return ret;
}

const _find_field = (obj, fieldName, deep) => {
	let ret = [];
	if (obj) {
		if (obj instanceof Array) {
			obj.forEach(_itm => {
				ret = ret.concat(_find_field(_itm, fieldName, deep));
			})
		} else {
			if (fieldName==='*') {
				if (typeof obj == 'object') {
					if (deep) ret.push(obj); // ".*" does not include current level (while " *" does)
					for (let i in obj) {
						ret.push(obj[i]);
						if (deep) ret = ret.concat(_find_field(obj[i], fieldName, true));
					}
				} else {
					ret.push(obj);
				}
			} else {
				if (obj[fieldName]) {
					if (obj[fieldName] instanceof Array) {
						ret = ret.concat(flatten(obj[fieldName]));
					} else {
						ret.push(flatten(obj[fieldName]));
					}
				}
				if (deep && typeof obj == 'object') {
					for (let i in obj)
						ret = ret.concat(_find_field(obj[i], fieldName, true));
				}
			}
		}
	}
	return ret;
}

const _obj_pseudo = (obj, pseudoName, opt) => {
	let localPseudo = Object.assign({}, pseudo, (opt || {}).pseudo);

	const func = localPseudo[pseudoName] || function(){return obj};
	return func(obj);
}

//remove items of multiple values (i.e. from arrays) that does not satisfies filter (at any level of nested of object)
const _obj_filter = (obj, filter, opt) => {
	const filterParsed = parse_filter(filter, opt);

	if (!filterParsed.left) {
		return obj;
	}

	if (!_obj_satisfies_filter(obj, filterParsed, opt)) {
		return;
	} else {
		return deep_filter(obj, (_itm, parent, parent_key) => {
			if (_itm instanceof Array) {
				let filtered = [];
				if (!parent) {
					for (let i=0; i<_itm.length; i++) {
						if (_obj_satisfies_filter(_itm[i], filterParsed, opt)) filtered.push(_itm[i]);
					}
				} else {
					//by the way, parent[parent_key] == _itm, _itm is array
					let saved = parent[parent_key];

					const parent_backup = (parent instanceof Array ? [] : {});
					const parent_keys = Object.keys(parent);
					for (let j in parent) {
						parent_backup[j] = parent[j];
						parent[j] = undefined;
					}

					for (let i=0; i<saved.length; i++) {
						parent[parent_key] = [saved[i]];
						if (_obj_satisfies_filter(obj, filterParsed, opt)) {
							filtered.push(saved[i]);
						}
					}

					for (let j in parent_backup) {
						parent[j] = parent_backup[j];
					}
					parent[parent_key] = filtered;
				}
				_itm = filtered;
			}
			return _itm
		});
	}
}

//is 'obj' satisfies 'filter' condition
//(filter can be like this "a.b.c=d", that means obj.a.b.c = d)
//(if obj.a.b.c returns array (look at _get) then it returns true if it contains filter value)
const _obj_satisfies_filter = (obj, filterParsed, opt) => {
	let localOperator = Object.assign({}, operator, (opt || {}).operator);

	const complexField = filterParsed.left;
	const value = filterParsed.right;
	const equal = localOperator[filterParsed.delimiter] || function(){};

	let complexFieldValue = _get(obj, parse(complexField), opt);

	return equal(complexFieldValue, value);
}

module.exports = { get };
<|endoftext|>


<commit_before>let WebpackExtractPlugin = require('extract-text-webpack-plugin')

class ExtractTextPluginFactory {
    /**
     * Create a new class instance.
     *
     * @param {string|boolean} cssPath
     */
    constructor(mix, cssPath) {
        if (typeof cssPath === 'boolean') {
            cssPath = path.join(global.scripts.base || '', 'vue-styles.css');

            this.useDefault = true;
        }

        this.mix = mix;
        this.path = cssPath;
    }

    /**
     * Build up the necessary ExtractTextPlugin instance.
     */
    build() {
        if (this.mix.preprocessors) {
            // If no output path is provided, we can use the default plugin.
            if (this.useDefault) return this.mix.preprocessors[0].getExtractPlugin();

            // If what the user passed matches the output to mix.preprocessor(),
            // then we can use that plugin instead and append to it.
            if (this.pluginIsAlreadyBuilt()) return this.getPlugin();
        }

        // Otherwise, we'll setup a new plugin to toss the styles into it.
        return new WebpackExtractPlugin(this.outputPath());
    }

    /**
     * Check if the the provided path is already registered as an extract instance.
     */
    pluginIsAlreadyBuilt() {
        return this.mix.preprocessors.find(
            preprocessor => preprocessor.output.path === this.path
        );
    }

    /**
     * Fetch the Extract plugin instance that matches the current output path.
     */
    getPlugin() {
        return this.mix.preprocessors.find(
            preprocessor => preprocessor.getExtractPlugin().filename === this.outputPath()
        ).getExtractPlugin();
    }

    /**
     * Prepare the appropriate output path.
     */
    outputPath() {
        let segments = new File(this.path).parsePath();

        let regex = new RegExp('^(\.\/)?' + global.options.publicPath);
        let pathVariant = global.options.versioning ? 'hashedPath' : 'path';

        return segments[pathVariant].replace(regex, '').replace(/\\/g, '/');
    }
}

module.exports = ExtractTextPluginFactory;
<commit_msg>Fix property name<commit_after>let WebpackExtractPlugin = require('extract-text-webpack-plugin')

class ExtractTextPluginFactory {
    /**
     * Create a new class instance.
     *
     * @param {string|boolean} cssPath
     */
    constructor(mix, cssPath) {
        if (typeof cssPath === 'boolean') {
            cssPath = path.join(global.entry.base || '', 'vue-styles.css');

            this.useDefault = true;
        }

        this.mix = mix;
        this.path = cssPath;
    }

    /**
     * Build up the necessary ExtractTextPlugin instance.
     */
    build() {
        if (this.mix.preprocessors) {
            // If no output path is provided, we can use the default plugin.
            if (this.useDefault) return this.mix.preprocessors[0].getExtractPlugin();

            // If what the user passed matches the output to mix.preprocessor(),
            // then we can use that plugin instead and append to it.
            if (this.pluginIsAlreadyBuilt()) return this.getPlugin();
        }

        // Otherwise, we'll setup a new plugin to toss the styles into it.
        return new WebpackExtractPlugin(this.outputPath());
    }

    /**
     * Check if the the provided path is already registered as an extract instance.
     */
    pluginIsAlreadyBuilt() {
        return this.mix.preprocessors.find(
            preprocessor => preprocessor.output.path === this.path
        );
    }

    /**
     * Fetch the Extract plugin instance that matches the current output path.
     */
    getPlugin() {
        return this.mix.preprocessors.find(
            preprocessor => preprocessor.getExtractPlugin().filename === this.outputPath()
        ).getExtractPlugin();
    }

    /**
     * Prepare the appropriate output path.
     */
    outputPath() {
        let segments = new File(this.path).parsePath();

        let regex = new RegExp('^(\.\/)?' + global.options.publicPath);
        let pathVariant = global.options.versioning ? 'hashedPath' : 'path';

        return segments[pathVariant].replace(regex, '').replace(/\\/g, '/');
    }
}

module.exports = ExtractTextPluginFactory;
<|endoftext|>


<commit_before>var restify = require('restify');
var bunyan = require('bunyan');
var q = require('q');
var debug = require('debug')('bravado:server');
var path = require('path');
var inflection = require('inflection');
var package = require('../package.json');
var config = require('./config');
var bravado = require('bravado-core');
var cors = require('./cors');
var routeHandler = require('./route');
var indexRouteHandler = require('./index-route');

var server = undefined;

module.exports = {

  start: function (api, options) {
    debug('starting server');
    if (options) {
      config.load(options);
      config.validate({strict: true});
    }

    var serverOptions = {
      name: config.get('name'),
      version: package.version
    };

    server = restify.createServer(serverOptions);
    server.use(restify.queryParser({ mapParams: false }));
    server.use(restify.gzipResponse());
    server.use(restify.bodyParser({
      mapParams: false,
      mapFiles: false
    }));

    // load api definitions
    var loadPromise;
    if ('string' === typeof api) {
      loadPromise = bravado.ApiDefinition.load(api);
    } else if (Array.isArray(api)) {
      loadPromise = q.all(api.map(function (item) {
        return bravado.ApiDefinition.load(item);
      }));
    }

    return loadPromise
      .then(function (defs) {
        var routes = {};
        debug('api definition loaded: %j', api);
        if (!Array.isArray(defs)) {
          defs = [defs];
        }
        defs.forEach(function (def) {
          def.validate();
          var resourcePath = path.resolve(path.dirname(def['x-bravado-sourceFile']), config.get('path'));
          for (var r in def.resources) {
            var resource = def.resources[r];
            var controllerPath = path.resolve(resourcePath, resource['x-bravado-controller']);
            for (var a in resource.actions) {
              var action = resource.actions[a];
              var method = action.method.toLowerCase();
              if (method === 'delete') { method = 'del'; }
              if (method === 'options') { method = 'opts'; }
              var fullPath = action['x-bravado-fullPath'];
              var routePath = fullPath.replace(/\{((?:[\w.~-]|(?:%[0-9A-F]{2}))+)\}/g, ':$1');
              if (!routes[routePath]) {
                routes[routePath] = [];
              }
              routes[routePath].push({
                name: [r, a].join('.'),
                method: method,
                version: def.info.version,
                handler: routeHandler(def, r, a, require(controllerPath), options.context)
              });
            }
          }
          routes[def.basePath] = [{
            name: 'index',
            method: 'get',
            version: def.info.version,
            handler: indexRouteHandler(def)
          }];
        });
        Object.keys(routes).sort().reverse().forEach(function (routePath) {
          routes[routePath].forEach(function (route) {
            debug('routing %s@%s for %s', routePath, route.version, route.name);
            server.opts(routePath, cors.preflight());
            server[route.method](
              { path: routePath, version: route.version },
              cors.headers(),
              route.handler
            );
          });
        });
        return q.resolve();
      })
      .then(function () {
        var logger = restify.auditLogger({
          log: bunyan.createLogger({
            name: 'audit',
            stream: process.stdout
          })
        });
        server.on('after', function (req, res, route, err) {
          logger(req, res, route, err);
        });
        server.on('NotFound', function (req, res, err, cb) {
          res.send(404, { type: 'NotFound', message: err.message });
          cb();
        });
        server.on('MethodNotAllowed', function (req, res, err, cb) {
          res.send(405, { type: 'MethodNotAllowed', message: err.message });
          cb();
        });
        server.on('VersionNotAllowed', function (req, res, err, cb) {
          res.send(400, { type: 'VersionNotAllowed', message: err.message });
          cb();
        });
        server.on('InternalServer', function (req, res, err, cb) {
          res.send(500, { type: 'ServerError', message: err.message });
          cb();
        });
        server.on('uncaughtException', function (req, res, route, err) {
          logger(req, res, route, err);
          res.send(err.statusCode || 500, { type: err.type || 'Error', message: err.message });
        });

        server.listen(
          config.get('port'),
          config.get('host'),
          function () {
            debug('%s listening at %s', server.name, server.url);
          }
        );
      }).catch(function (err) {
        console.log(err.stack);
      });
  },

  stop: function () {
    debug('stopping server');
    server.close();
  }

};
<commit_msg>returns server object on server.start<commit_after>var restify = require('restify');
var bunyan = require('bunyan');
var q = require('q');
var debug = require('debug')('bravado:server');
var path = require('path');
var inflection = require('inflection');
var package = require('../package.json');
var config = require('./config');
var bravado = require('bravado-core');
var cors = require('./cors');
var routeHandler = require('./route');
var indexRouteHandler = require('./index-route');

var server = undefined;

module.exports = {

  start: function (api, options) {
    debug('starting server');
    if (options) {
      config.load(options);
      config.validate({strict: true});
    }

    var serverOptions = {
      name: config.get('name'),
      version: package.version
    };

    server = restify.createServer(serverOptions);
    server.use(restify.queryParser({ mapParams: false }));
    server.use(restify.gzipResponse());
    server.use(restify.bodyParser({
      mapParams: false,
      mapFiles: false
    }));

    // load api definitions
    var loadPromise;
    if ('string' === typeof api) {
      loadPromise = bravado.ApiDefinition.load(api);
    } else if (Array.isArray(api)) {
      loadPromise = q.all(api.map(function (item) {
        return bravado.ApiDefinition.load(item);
      }));
    }

    return loadPromise
      .then(function (defs) {
        var routes = {};
        debug('api definition loaded: %j', api);
        if (!Array.isArray(defs)) {
          defs = [defs];
        }
        defs.forEach(function (def) {
          def.validate();
          var resourcePath = path.resolve(path.dirname(def['x-bravado-sourceFile']), config.get('path'));
          for (var r in def.resources) {
            var resource = def.resources[r];
            var controllerPath = path.resolve(resourcePath, resource['x-bravado-controller']);
            for (var a in resource.actions) {
              var action = resource.actions[a];
              var method = action.method.toLowerCase();
              if (method === 'delete') { method = 'del'; }
              if (method === 'options') { method = 'opts'; }
              var fullPath = action['x-bravado-fullPath'];
              var routePath = fullPath.replace(/\{((?:[\w.~-]|(?:%[0-9A-F]{2}))+)\}/g, ':$1');
              if (!routes[routePath]) {
                routes[routePath] = [];
              }
              routes[routePath].push({
                name: [r, a].join('.'),
                method: method,
                version: def.info.version,
                handler: routeHandler(def, r, a, require(controllerPath), options.context)
              });
            }
          }
          routes[def.basePath] = [{
            name: 'index',
            method: 'get',
            version: def.info.version,
            handler: indexRouteHandler(def)
          }];
        });
        Object.keys(routes).sort().reverse().forEach(function (routePath) {
          routes[routePath].forEach(function (route) {
            debug('routing %s@%s for %s', routePath, route.version, route.name);
            server.opts(routePath, cors.preflight());
            server[route.method](
              { path: routePath, version: route.version },
              cors.headers(),
              route.handler
            );
          });
        });
        return q.resolve();
      })
      .then(function () {
        var logger = restify.auditLogger({
          log: bunyan.createLogger({
            name: 'audit',
            stream: process.stdout
          })
        });
        server.on('after', function (req, res, route, err) {
          logger(req, res, route, err);
        });
        server.on('NotFound', function (req, res, err, cb) {
          res.send(404, { type: 'NotFound', message: err.message });
          cb();
        });
        server.on('MethodNotAllowed', function (req, res, err, cb) {
          res.send(405, { type: 'MethodNotAllowed', message: err.message });
          cb();
        });
        server.on('VersionNotAllowed', function (req, res, err, cb) {
          res.send(400, { type: 'VersionNotAllowed', message: err.message });
          cb();
        });
        server.on('InternalServer', function (req, res, err, cb) {
          res.send(500, { type: 'ServerError', message: err.message });
          cb();
        });
        server.on('uncaughtException', function (req, res, route, err) {
          logger(req, res, route, err);
          res.send(err.statusCode || 500, { type: err.type || 'Error', message: err.message });
        });

        server.listen(
          config.get('port'),
          config.get('host'),
          function () {
            debug('%s listening at %s', server.name, server.url);
          }
        );

        return server;

      }).catch(function (err) {
        debug(err);
        throw err;
      });

  },

  stop: function () {
    debug('stopping server');
    server.close();
  }

};
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var Emitter = require('events').EventEmitter;
var compose = require('koa-compose');
var debug = require('debug')('fax');
var qs = require('querystring');
var assert = require('assert');
var xhr = require('xhr');
var co = require('co');

var response = require('./response');
var context = require('./context');
var request = require('./request');

/**
 * Store prototype.
 */

var app = Application.prototype;

/**
 * Expose `Store`.
 */

exports = module.exports = Application;

/**
 * Initialize a new `Store`.
 *
 * @api public
 */

function Application() {
  if (!(this instanceof Application)) return new Application;
  this.env = process.env.NODE_ENV || 'development';
  this._middleware = [];
  this.context = Object.create(context);
  this.request = Object.create(request);
  this.response = Object.create(response);
}

/**
 * Inherit from `Emitter.prototype`.
 */

Application.prototype.__proto__ = Emitter.prototype;

/**
 * Use the given middleware `fn`.
 *
 * @param {GeneratorFunction} fn
 * @return {Application} self
 * @api public
 */

app.use = function(fn) {
  assert(fn && 'GeneratorFunction' == fn.constructor.name, 'app.use() requires a generator function');
  debug('use %s', fn._name || fn.name || '-');
  this._middleware.push(fn);
  return this;
};

/**
 * Start the whole shebang.
 *
 * @return {Function}
 * @api public
 */

app.send = function(req) {
  var mw = this._middleware.concat([xhrmw]);
  var gen = compose(mw);
  var fn = co(gen);

  assert(!req || 'object' == typeof req, 'Request should be an object');

  if (!this.listeners('error').length) this.on('error', this.onerror);

  var ctx = this.createContext(req);
  fn.call(ctx);
};

/**
 * Initialize a new context.
 *
 * @param {Object} req
 * @api private
 */

app.createContext = function(req) {
  req = req || {};
  req.method = req.method || 'GET';
  req.headers = req.headers || {};
  req.url = req.url || '';

  assert('object' == typeof req, 'fax: req should be an object');

  var context = Object.create(this.context);
  var request = context.request = Object.create(this.request);
  var response = context.response = Object.create(this.response);

  context.app = request.app = response.app = this;
  context.req = request.req = response.req = req;
  context.res = request.res = response.res = {};
  request.ctx = response.ctx = context;

  request.response = response;
  response.request = request;

  context.originalUrl = request.originalUrl = req.url;
  context.onerror = context.onerror.bind(context);

  return context;
}

/**
 * Default error handler.
 *
 * @param {Error} err
 * @api private
 */

app.onerror = function(err) {
  assert(err instanceof Error, 'non-error thrown: ' + err);

  if (404 == err.status) return;
  if ('test' == this.env) return;

  var msg = err.stack || err.toString();
  console.error();
  console.error(msg.replace(/^/gm, '  '));
  console.error();
};

/**
 * XHR middleware.
 *
 * @param {Function} next
 * @api private
 */

function *xhrmw(next) {
  if (!this.url) return yield next;

  var opts = {
    url: this.url,
    body: this.body,
    method: this.method,
    headers: this.headers
  };
  console.log(this.req)
  var thunk = xhr.bind(null, opts);
  var response = yield thunk;

  var res = response[0];
  if (res instanceof Error) throw res;

  Object.keys(res).forEach(function(key) {
    this.res[key] = res[key];
  }.bind(this));

  yield next;
}
<commit_msg>console.log: derp, fixing<commit_after>/**
 * Module dependencies
 */

var Emitter = require('events').EventEmitter;
var compose = require('koa-compose');
var debug = require('debug')('fax');
var qs = require('querystring');
var assert = require('assert');
var xhr = require('xhr');
var co = require('co');

var response = require('./response');
var context = require('./context');
var request = require('./request');

/**
 * Store prototype.
 */

var app = Application.prototype;

/**
 * Expose `Store`.
 */

exports = module.exports = Application;

/**
 * Initialize a new `Store`.
 *
 * @api public
 */

function Application() {
  if (!(this instanceof Application)) return new Application;
  this.env = process.env.NODE_ENV || 'development';
  this._middleware = [];
  this.context = Object.create(context);
  this.request = Object.create(request);
  this.response = Object.create(response);
}

/**
 * Inherit from `Emitter.prototype`.
 */

Application.prototype.__proto__ = Emitter.prototype;

/**
 * Use the given middleware `fn`.
 *
 * @param {GeneratorFunction} fn
 * @return {Application} self
 * @api public
 */

app.use = function(fn) {
  assert(fn && 'GeneratorFunction' == fn.constructor.name, 'app.use() requires a generator function');
  debug('use %s', fn._name || fn.name || '-');
  this._middleware.push(fn);
  return this;
};

/**
 * Start the whole shebang.
 *
 * @return {Function}
 * @api public
 */

app.send = function(req) {
  var mw = this._middleware.concat([xhrmw]);
  var gen = compose(mw);
  var fn = co(gen);

  assert(!req || 'object' == typeof req, 'Request should be an object');

  if (!this.listeners('error').length) this.on('error', this.onerror);

  var ctx = this.createContext(req);
  fn.call(ctx);
};

/**
 * Initialize a new context.
 *
 * @param {Object} req
 * @api private
 */

app.createContext = function(req) {
  req = req || {};
  req.method = req.method || 'GET';
  req.headers = req.headers || {};
  req.url = req.url || '';

  assert('object' == typeof req, 'fax: req should be an object');

  var context = Object.create(this.context);
  var request = context.request = Object.create(this.request);
  var response = context.response = Object.create(this.response);

  context.app = request.app = response.app = this;
  context.req = request.req = response.req = req;
  context.res = request.res = response.res = {};
  request.ctx = response.ctx = context;

  request.response = response;
  response.request = request;

  context.originalUrl = request.originalUrl = req.url;
  context.onerror = context.onerror.bind(context);

  return context;
}

/**
 * Default error handler.
 *
 * @param {Error} err
 * @api private
 */

app.onerror = function(err) {
  assert(err instanceof Error, 'non-error thrown: ' + err);

  if (404 == err.status) return;
  if ('test' == this.env) return;

  var msg = err.stack || err.toString();
  console.error();
  console.error(msg.replace(/^/gm, '  '));
  console.error();
};

/**
 * XHR middleware.
 *
 * @param {Function} next
 * @api private
 */

function *xhrmw(next) {
  if (!this.url) return yield next;

  var opts = {
    url: this.url,
    body: this.body,
    method: this.method,
    headers: this.headers
  };

  var thunk = xhr.bind(null, opts);
  var response = yield thunk;

  var res = response[0];
  if (res instanceof Error) throw res;

  Object.keys(res).forEach(function(key) {
    this.res[key] = res[key];
  }.bind(this));

  yield next;
}
<|endoftext|>


<commit_before>/*jslint indent: 2*/
/*global require: true, module: true*/
(function () {
  'use strict';

  var InvalidInputError = require('./input-error.js'),
    transformationFunctions = require('./transforms'),
    transformationKeys = require('./keys'),
    regex =  /^(\d*)d(\d+|\%)(([\+\-\/\*bw])(\d+))?(([\+\-\/\*])(\d+|(\d*)d(\d+|\%)(([\+\-\/\*bw])(\d+))?))*$/,
    roll,
    cleaner,
    sumResult = false;

  roll = function (random) {
    this.random = random || function () {
      return Math.random();
    };
  };

  roll.prototype.validate = function (s) {
    return regex.test(s);
  };

  roll.prototype.parse = function (s) {
    if (!this.validate(s)) {
      throw new InvalidInputError(s);
    }

    var match = regex.exec(s),
      quantity = match[1], // 2d20+3 => 2
      sides = match[2], // 2d20+3 => 20
      hasTransformation = !!match[3], // 2d20+3 => true
      operator,
      transformationParameter,
      transforms = [],
      opIndex = 0,
      segments = s.split(/[\+\-]/);

    if (segments[0].indexOf('b') > -1) {
      transforms.push(transformationKeys[match[4]](parseInt(match[5], 10)));
    }
    for (var seg = 1; seg < segments.length; seg++) {
      opIndex += segments[seg - 1].length;
      operator = s[opIndex]; // 2d20+3 => "+"
      opIndex += 1;
      transformationParameter = segments[seg]; // 2d20+3 => 3
      if (transformationParameter.indexOf('d') > -1) {
        transforms.push(transformationKeys[operator](parseInt(this.roll(transformationParameter).result, 10)));
      } else {
        transforms.push(transformationKeys[operator](parseInt(transformationParameter, 10)));
      }
    }

    return {
      quantity: quantity ? parseInt(quantity, 10) : 1,
      sides: sides === '%' ? 100 : parseInt(sides, 10),
      transformations: hasTransformation || transforms.length > 0 ? transforms.length > 0 ? transforms : transformationKeys[match[4]](parseInt(match[5], 10)) : ['sum'],
      toString: function () {
        return s;
      }
    };
  };

  roll.prototype.roll = function (input) {
    if (!input) {
      throw new InvalidInputError();
    } else if (typeof input === 'string') {
      input = this.parse(input);
    }

    var rolled = [],
     calculations = [];

    while (rolled.length < input.quantity) {
      rolled.push(Math.floor((this.random() * input.sides) + 1));
    }

    calculations = input.transformations.reduce(function (previous, transformation) {
      var transformationFunction,
        transformationAdditionalParameter,
        sumParam = false;

      if (typeof transformation === 'function') { // lets you pass something custom in
        transformationFunction = transformation;
      } else if (typeof transformation === 'string') { // "sum"
        transformationFunction = transformationFunctions[transformation];
      } else if (transformation instanceof Array) { // ["add", 3]
        if (transformation[0] instanceof Array) {
          sumResult = true;
          cleaner = transformation[1];
          transformation = transformation[0];
        } else if (transformation[1] instanceof Array) {
          sumParam = true;
          cleaner = transformation[0];
          transformation = transformation[1];
        }
        transformationFunction = transformationFunctions[transformation[0]]; // fn for "add"
        transformationAdditionalParameter = transformation[1];
      }
      if (sumParam === true && previous[0]  instanceof Array){
        previous[0] = transformationFunctions[cleaner](previous[0]);
      }
      previous.unshift(transformationFunction(previous[0], transformationAdditionalParameter));
      return previous;
    }, [rolled]);

    if (sumResult === true && calculations[0] instanceof Array) {
      calculations[0] = transformationFunctions[cleaner](calculations[0]);
    }

    return {
      input: input,
      calculations: calculations,
      rolled: calculations[calculations.length - 1],
      result: calculations[0]
    };
  };

  module.exports = roll;
  module.exports.InvalidInputError = InvalidInputError;

}());

<commit_msg>address outstanding test case<commit_after>/*jslint indent: 2*/
/*global require: true, module: true*/
(function () {
  'use strict';

  var InvalidInputError = require('./input-error.js'),
    transformationFunctions = require('./transforms'),
    transformationKeys = require('./keys'),
    regex =  /^(\d*)d(\d+|\%)(([\+\-\/\*bw])(\d+))?(([\+\-\/\*])(\d+|(\d*)d(\d+|\%)(([\+\-\/\*bw])(\d+))?))*$/,
    roll,
    cleaner,
    sumResult = false;

  roll = function (random) {
    this.random = random || function () {
      return Math.random();
    };
  };

  roll.prototype.validate = function (s) {
    return regex.test(s);
  };

  roll.prototype.parse = function (s) {
    if (!this.validate(s)) {
      throw new InvalidInputError(s);
    }

    var match = regex.exec(s),
      quantity = match[1], // 2d20+3 => 2
      sides = match[2], // 2d20+3 => 20
      hasTransformation = !!match[3], // 2d20+3 => true
      operator,
      transformationParameter,
      transforms = [],
      opIndex = 0,
      segments = s.split(/[\+\-]/);

    if (segments[0].indexOf('b') > -1) {
      transforms.push(transformationKeys[match[4]](parseInt(match[5], 10)));
    }
    for (var seg = 1; seg < segments.length; seg++) {
      opIndex += segments[seg - 1].length;
      operator = s[opIndex]; // 2d20+3 => "+"
      opIndex += 1;
      transformationParameter = segments[seg]; // 2d20+3 => 3
      if (transformationParameter.indexOf('d') > -1) {
        transforms.push(transformationKeys[operator](parseInt(this.roll(transformationParameter).result, 10)));
      } else {
        transforms.push(transformationKeys[operator](parseInt(transformationParameter, 10)));
      }
    }

    return {
      quantity: quantity ? parseInt(quantity, 10) : 1,
      sides: sides === '%' ? 100 : parseInt(sides, 10),
      transformations: hasTransformation || transforms.length > 0 ? transforms.length > 0 ? transforms : transformationKeys[match[4]](parseInt(match[5], 10)) : ['sum'],
      toString: function () {
        return s;
      }
    };
  };

  roll.prototype.roll = function (input) {
    if (!input) {
      throw new InvalidInputError();
    } else if (typeof input === 'string') {
      input = this.parse(input);
    }

    var rolled = [],
     calculations = [];

    while (rolled.length < input.quantity) {
      rolled.push(Math.floor((this.random() * input.sides) + 1));
    }

    calculations = input.transformations.reduce(function (previous, transformation) {
      var transformationFunction,
        transformationAdditionalParameter,
        sumParam = false;

      if (typeof transformation === 'function') { // lets you pass something custom in
        transformationFunction = transformation;
      } else if (typeof transformation === 'string') { // "sum"
        transformationFunction = transformationFunctions[transformation];
      } else if (transformation instanceof Array) { // ["add", 3]
        if (transformation[0] instanceof Array) {
          sumResult = true;
          cleaner = transformation[1];
          transformation = transformation[0];
        } else if (transformation[1] instanceof Array) {
          sumParam = true;
          cleaner = transformation[0];
          transformation = transformation[1];
        }
        transformationFunction = transformationFunctions[transformation[0]]; // fn for "add"
        transformationAdditionalParameter = transformation[1];
      }
      if (sumParam === true && previous[0]  instanceof Array){
        previous[0] = transformationFunctions[cleaner](previous[0]);
      }
      previous.unshift(transformationFunction(previous[0], transformationAdditionalParameter));
      return previous;
    }, [rolled]);

    if (sumResult === true && calculations[0] instanceof Array) {
      calculations[1] = calculations[0];
      calculations[0] = transformationFunctions[cleaner](calculations[0]);
    }

    return {
      input: input,
      calculations: calculations,
      rolled: calculations[calculations.length - 1],
      result: calculations[0]
    };
  };

  module.exports = roll;
  module.exports.InvalidInputError = InvalidInputError;

}());

<|endoftext|>


<commit_before>var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

var Ball = function(x, y, radius, context) {
  this.x = x;
  this.y = y;
  this.radius = radius || 10;
  this.startAngle = 0;
  this.endAngle = (Math.PI * 2);
  this.context = context
  this.speed = 1
  this.xDirection = 1
  this.yDirection = 1
}

var Bumper = function(x, y, height, width, context) {
  this.x = x;
  this.y = y;
  this.height = height;
  this.width = width;
  this.context = context
};

// var obstacle = new Bumper(250, 500, 60, 300);
var obstacleTwo = new Bumper(550, 10, 500, 10);

// var obstacles = [obstacle, obstacleTwo]
// var obstacles = [obstacle]

Bumper.prototype.draw = function() {
  obstacles.forEach(function (obstacle, index) {
    context.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
    return obstacle;
  });
};

Ball.prototype.draw = function () {
    context.arc(this.x, this.y, this.radius, this.startAngle, this.endAngle);
    context.fillStyle = "white"
    context.fill();
    return this;
};

Ball.prototype.move = function () {

  if(this.xDirection == 1) {
    this.posXBounce();
  }
  else {
    this.negXBounce();
  }

  if (this.yDirection == 1) {
    this.posYBounce();
  }
  else {
    this.negYBounce();
  }

  this.x = this.x + (this.speed * this.xDirection);
  this.y = this.y + (this.speed * this.yDirection);

  return this;
}

Ball.prototype.posXBounce = function() {

  if (this.x + this.radius >= canvas.width || (this.x + this.radius == obstacle.x && this.y + this.radius <= obstacle.y + obstacle.height && this.y + this.radius >= obstacle.y)) {
    // debugger;
    this.xDirection = -1;
    this.speed *= 0.8
  }
}

Ball.prototype.negXBounce = function() {
  if (this.x - this.radius < 0 || (this.x - this.radius == obstacle.x + obstacle.width && this.y + this.radius <= obstacle.y + obstacle.height && this.y + this.radius >= obstacle.y)) {
    // debugger;
    this.xDirection = 1;
    this.speed *= 0.8
  }
}

Ball.prototype.posYBounce = function() {
  if (this.y >= canvas.height - this.radius || this.y + this.radius == obstacle.y && this.x + this.radius <= obstacle.x + obstacle.width && this.x - this.radius >= obstacle.x) {
    // debugger;
    this.yDirection = -1;
  }
}

// The Code Below Is Correct!!
Ball.prototype.negYBounce = function() {
  if (this.y - this.radius < 0 || (this.y - this.radius == obstacle.y + obstacle.height && this.x + this.radius <= obstacle.x + obstacle.width && this.x - this.radius >= obstacle.x)){
    // debugger;
    this.yDirection = 1;
  }
}
// Ball.prototype.move = function () {
//   this.x = this.x + (this.speed * this.xDirection);
//   this.y = this.y + (this.speed * this.yDirection);
//
//   if (this.x >= canvas.width - this.radius || this.x < 0 || this.x == obstacle.x - this.radius) {
//     this.xDirection *= -1;
//     this.speed *= 0.8
//   }
//   if (this.y >= canvas.height - this.radius || this.y < 0|| this.y == obstacle.y - this.radius) {
//     this.yDirection *= -1;
//   }
//   return this;
// };

// X Bounce Obstacles!!
//left side
// var obstacle = new Bumper(50, 20, 500, 10);
// var golfBall = new Ball(10, 10, 6, 0);

// right side
var obstacle = new Bumper(650, 20, 500, 10);
var golfBall = new Ball(670, 10, 6, 0);
// var obstacles = [obstacle]

// var obstacleTwo = new Bumper(50, 450, 10, 400);
// var obstacles = [obstacle, obstacleTwo]

// Y Bounce Obstacles!!

// Top obstacle
// var obstacle = new Bumper(50, 50, 10, 400);
// var golfBall = new Ball(50, 30, 6, 0);

// Bottom Obstacle
// var obstacle = new Bumper(50, 550, 10, 400);
// var golfBall = new Ball(50, 570, 6, 0);

var obstacles = [obstacle]
// var obstacleTwo = new Bumper(50, 450, 10, 400);
// var obstacles = [obstacle, obstacleTwo]

requestAnimationFrame(function gameLoop() {
  context.beginPath();
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.closePath();
  obstacle.draw();
  golfBall.draw().move();
  requestAnimationFrame(gameLoop);
});

module.exports = Ball;
<commit_msg>Add Hole Obstacles and move ball<commit_after>var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

var Ball = function(x, y, radius, context) {
  this.x = x;
  this.y = y;
  this.radius = radius || 10;
  this.startAngle = 0;
  this.endAngle = (Math.PI * 2);
  this.context = context
  this.speed = 1
  this.xDirection = 1
  this.yDirection = 1
}

var Bumper = function(x, y, height, width, context) {
  this.x = x;
  this.y = y;
  this.height = height;
  this.width = width;
  this.context = context
};

Bumper.prototype.draw = function() {
  obstacles.forEach(function (obstacle, index) {
    context.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
    // return obstacle;
  });
  return this;
};

Ball.prototype.draw = function () {
    context.arc(this.x, this.y, this.radius, this.startAngle, this.endAngle);
    context.fillStyle = "white"
    context.fill();
    return this;
};

// Hole Obstacles x-y-height-width
var obstacle = new Bumper(50, 50, 10, 200);
var obstacleTwo = new Bumper(50, 450, 10, 200);
var obstacleThree = new Bumper(50, 50, 400, 10);
var obstacleFour = new Bumper(250, 50, 410, 10);
var obstacles = [obstacle, obstacleTwo, obstacleThree, obstacleFour]

var golfBall = new Ball(175, 425, 6);

Ball.prototype.move = function () {

  if(this.xDirection == 1) {
    this.posXBounce();
  }
  else {
    this.negXBounce();
  }

  if (this.yDirection == 1) {
    this.posYBounce();
  }
  else {
    this.negYBounce();
  }

  this.x = this.x + (this.speed * this.xDirection);
  this.y = this.y + (this.speed * this.yDirection);

  return this;
}

Ball.prototype.posXBounce = function() {
  if (this.x + this.radius >= canvas.width || (this.x + this.radius == obstacle.x && this.y + this.radius <= obstacle.y + obstacle.height && this.y + this.radius >= obstacle.y)) {
    // debugger;
    this.xDirection = -1;
    this.speed *= 0.8
  }
}

Ball.prototype.negXBounce = function() {
  if (this.x - this.radius < 0 || (this.x - this.radius == obstacle.x + obstacle.width && this.y + this.radius <= obstacle.y + obstacle.height && this.y + this.radius >= obstacle.y)) {
    // debugger;
    this.xDirection = 1;
    this.speed *= 0.8
  }
}

Ball.prototype.posYBounce = function() {
  if (this.y >= canvas.height - this.radius || this.y + this.radius == obstacle.y && this.x + this.radius <= obstacle.x + obstacle.width && this.x - this.radius >= obstacle.x) {
    // debugger;
    this.yDirection = -1;
  }
}

Ball.prototype.negYBounce = function() {
  if (this.y - this.radius < 0 || (this.y - this.radius == obstacle.y + obstacle.height && this.x + this.radius <= obstacle.x + obstacle.width && this.x - this.radius >= obstacle.x)){
    // debugger;
    this.yDirection = 1;
  }
}
// Ball.prototype.move = function () {
//   this.x = this.x + (this.speed * this.xDirection);
//   this.y = this.y + (this.speed * this.yDirection);
//
//   if (this.x >= canvas.width - this.radius || this.x < 0 || this.x == obstacle.x - this.radius) {
//     this.xDirection *= -1;
//     this.speed *= 0.8
//   }
//   if (this.y >= canvas.height - this.radius || this.y < 0|| this.y == obstacle.y - this.radius) {
//     this.yDirection *= -1;
//   }
//   return this;
// };

// X Bounce Obstacles!!
//left side
// var obstacle = new Bumper(50, 20, 500, 10);
// var golfBall = new Ball(10, 10, 6, 0);

// right side
// var obstacle = new Bumper(650, 20, 500, 10);
// var golfBall = new Ball(670, 10, 6, 0);
// var obstacles = [obstacle]

// var obstacleTwo = new Bumper(50, 450, 10, 400);
// var obstacles = [obstacle, obstacleTwo]

// Y Bounce Obstacles!!

// Top obstacle
// var obstacle = new Bumper(50, 50, 10, 400);
// var golfBall = new Ball(50, 30, 6, 0);

// Bottom Obstacle
// var obstacle = new Bumper(50, 550, 10, 400);
// var golfBall = new Ball(50, 570, 6, 0);
//
// var obstacles = [obstacle]
// var obstacles = [obstacle, obstacleTwo, obstacleThree]
// var obstacleTwo = new Bumper(50, 450, 10, 400);

requestAnimationFrame(function gameLoop() {
  context.beginPath();
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.closePath();
  obstacle.draw();
  golfBall.draw().move();
  requestAnimationFrame(gameLoop);
});

module.exports = Ball;
<|endoftext|>


<commit_before>/**
 * matchAll
 * Get all the matches for a regular expression in a string.
 *
 * @name matchAll
 * @function
 * @param {String} s The input string.
 * @param {RegExp} r The regular expression.
 * @return {Object} An object containing the following fields:
 *
 *  - `input` (String): The input string.
 *  - `regex` (RegExp): The regular expression.
 *  - `next` (Function): Get the next match.
 *  - `toArray` (Function): Get all the matches.
 *  - `reset` (Function): Reset the index.
 */
module.exports = function matchAll (s, r) {
    return {
        input: s
      , regex: r

        /**
         * next
         * Get the next match in single group match.
         *
         * @name next
         * @function
         * @return {String|null} The matched snippet.
         */
      , next () {
            var c = this.nextRaw();
            if (c) {
              for (var i = 1; i < c.length; i++) {
                if (c[i]) return c[i];
              }
            } else return null;
        }

        /**
         * nextRaw
         * Get the next match in raw regex output. Usefull to get another group match.
         *
         * @name nextRaw
         * @function
         * @returns {Array|null} The matched snippet
         */
      , nextRaw () {
            var c = this.regex.exec(this.input);
            return c;
        }

        /**
         * toArray
         * Get all the matches.
         *
         * @name toArray
         * @function
         * @return {Array} The matched snippets.
         */
      , toArray () {
            var res = []
              , c = null
              ;

            while (c = this.next()) {
                res.push(c);
            }

            return res;
        }

        /**
         * reset
         * Reset the index.
         *
         * @name reset
         * @function
         * @param {Number} i The new index (default: `0`).
         * @return {Number} The new index.
         */
      , reset (i) {
            return this.regex.lastIndex = i || 0;
        }
    }
};
<commit_msg>Code style<commit_after>/**
 * matchAll
 * Get all the matches for a regular expression in a string.
 *
 * @name matchAll
 * @function
 * @param {String} s The input string.
 * @param {RegExp} r The regular expression.
 * @return {Object} An object containing the following fields:
 *
 *  - `input` (String): The input string.
 *  - `regex` (RegExp): The regular expression.
 *  - `next` (Function): Get the next match.
 *  - `toArray` (Function): Get all the matches.
 *  - `reset` (Function): Reset the index.
 */
module.exports = function matchAll (s, r) {
    return {
        input: s
      , regex: r

        /**
         * next
         * Get the next match in single group match.
         *
         * @name next
         * @function
         * @return {String|null} The matched snippet.
         */
      , next () {
            let c = this.nextRaw()
            if (c) {
                for (let i = 1; i < c.length; i++) {
                    if (c[i]) {
                        return c[i]
                    }
                }
            }
            return null
        }

        /**
         * nextRaw
         * Get the next match in raw regex output. Usefull to get another group match.
         *
         * @name nextRaw
         * @function
         * @returns {Array|null} The matched snippet
         */
      , nextRaw () {
            let c = this.regex.exec(this.input)
            return c
        }

        /**
         * toArray
         * Get all the matches.
         *
         * @name toArray
         * @function
         * @return {Array} The matched snippets.
         */
      , toArray () {
            let res = []
              , c = null

            while (c = this.next()) {
                res.push(c)
            }

            return res
        }

        /**
         * reset
         * Reset the index.
         *
         * @name reset
         * @function
         * @param {Number} i The new index (default: `0`).
         * @return {Number} The new index.
         */
      , reset (i) {
            return this.regex.lastIndex = i || 0
        }
    }
};
<|endoftext|>


<commit_before>/**
*
*	MINIMAL SVG ELEMENT
*
*
*	DESCRIPTION:
*		- Factory which creates minimal DOM-like SVG elements.
*
*
*	NOTES:
*		[1]
*
*
*	TODO:
*		[1]
*
*
*	LICENSE:
*		MIT
*
*	Copyright (c) 2014. Athan Reines.
*
*
*	AUTHOR:
*		Athan Reines. kgryte@gmail.com. 2014.
*
*/

(function() {
	'use strict';

	// MODULES //

	var // Parent class:
		Uber = require( 'minimal-element-class' ),

		// Dictionary of SVG elements:
		dict = require( 'svg-element-dictionary' );

	// SVG ELEMENT //

	/**
	* FUNCTION: Element( name )
	*	SVG element constructor.
	*
	* @constructor
	* @param {String} name - element name
	* @returns {Element} Element instance
	*/
	function Element( name ) {
		Uber.call( this );
		this._name = name;
		this._selfClosing = false;
		return this;
	} // end FUNCTION Element()

	/**
	* Create a prototype which inherits from the parent prototype.
	*/
	Element.prototype = Object.create( Uber.prototype );

	/**
	* Set the constructor.
	*/
	Element.prototype.constructor = Element;

	// EXPORTS //

	module.exports = function createSVGElement( name ) {
		if ( typeof name !== 'string' ) {
			throw new TypeError( 'createSVGElement()::invalid input argument. Name must be a string.' );
		}
		if ( !dict[ name ] ) {
			throw new Error( 'createSVGElement()::invalid input argument. Unrecognized SVG element name.' );
		}
		return new Element( name );
	};

})();<commit_msg>[UPDATE] documentation.<commit_after>/**
*
*	MINIMAL SVG ELEMENT
*
*
*	DESCRIPTION:
*		- Factory for creating minimal DOM-like SVG elements.
*
*
*	NOTES:
*		[1]
*
*
*	TODO:
*		[1]
*
*
*	LICENSE:
*		MIT
*
*	Copyright (c) 2014. Athan Reines.
*
*
*	AUTHOR:
*		Athan Reines. kgryte@gmail.com. 2014.
*
*/

(function() {
	'use strict';

	// MODULES //

	var // Parent class:
		Uber = require( 'minimal-element-class' ),

		// Dictionary of SVG elements:
		dict = require( 'svg-element-dictionary' );

	// SVG ELEMENT //

	/**
	* FUNCTION: Element( name )
	*	SVG element constructor.
	*
	* @constructor
	* @param {String} name - element name
	* @returns {Element} Element instance
	*/
	function Element( name ) {
		Uber.call( this );
		this._name = name;
		this._selfClosing = false;
		return this;
	} // end FUNCTION Element()

	/**
	* Create a prototype which inherits from the parent prototype.
	*/
	Element.prototype = Object.create( Uber.prototype );

	/**
	* Set the constructor.
	*/
	Element.prototype.constructor = Element;

	// EXPORTS //

	module.exports = function createSVGElement( name ) {
		if ( typeof name !== 'string' ) {
			throw new TypeError( 'createSVGElement()::invalid input argument. Name must be a string.' );
		}
		if ( !dict[ name ] ) {
			throw new Error( 'createSVGElement()::invalid input argument. Unrecognized SVG element name.' );
		}
		return new Element( name );
	};

})();<|endoftext|>