text: /*!
   * body-parser
   * Copyright(c) 2014 Jonathan Ong
   * Copyright(c) 2014-2015 Douglas Christopher Wilson
   * MIT Licensed
   */
  
  'use strict'
  
  /**
   * Module dependencies.
   * @private
   */
  
  var bytes = require('bytes')
  var contentType = require('content-type')
  var createError = require('http-errors')
  var debug = require('debug')('body-parser:urlencoded')
  var deprecate = require('depd')('body-parser')
  var read = require('../read')
  var typeis = require('type-is')
  
  /**
   * Module exports.
   */
  
  module.exports = urlencoded
  
  /**
   * Cache of parser modules.
   */
  
  var parsers = Object.create(null)
  
  /**
   * Create a middleware to parse urlencoded bodies.
   *
   * @param {object} [options]
   * @return {function}
   * @public
   */
  
  function urlencoded (options) {
    var opts = options || {}
  
    // notice because option default will flip in next major
    if (opts.extended === undefined) {
      deprecate('undefined extended: provide extended option')
    }
  
    var extended = opts.extended !== false
    var inflate = opts.inflate !== false
    var limit = typeof opts.limit !== 'number'
      ? bytes.parse(opts.limit || '100kb')
      : opts.limit
    var type = opts.type || 'application/x-www-form-urlencoded'
    var verify = opts.verify || false
  
    if (verify !== false && typeof verify !== 'function') {
      throw new TypeError('option verify must be function')
    }
  
    // create the appropriate query parser
    var queryparse = extended
      ? extendedparser(opts)
      : simpleparser(opts)
  
    // create the appropriate type checking function
    var shouldParse = typeof type !== 'function'
      ? typeChecker(type)
      : type
  
    function parse (body) {
      return body.length
        ? queryparse(body)
        : {}
    }
  
    return function urlencodedParser (req, res, next) {
      if (req._body) {
        debug('body already parsed')
        next()
        return
      }
  
      req.body = req.body || {}
  
      // skip requests without bodies
      if (!typeis.hasBody(req)) {
        debug('skip empty body')
        next()
        return
      }
  
      debug('content-type %j', req.headers['content-type'])
  
      // determine if request should be parsed
      if (!shouldParse(req)) {
        debug('skip parsing')
        next()
        return
      }
  
      // assert charset
      var charset = getCharset(req) || 'utf-8'
      if (charset !== 'utf-8') {
        debug('invalid charset')
        next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
          charset: charset,
          type: 'charset.unsupported'
        }))
        return
      }
  
      // read
      read(req, res, next, parse, debug, {
        debug: debug,
        encoding: charset,
        inflate: inflate,
        limit: limit,
        verify: verify
      })
    }
  }
  
  /**
   * Get the extended query parser.
   *
   * @param {object} options
   */
  
  function extendedparser (options) {
    var parameterLimit = options.parameterLimit !== undefined
      ? options.parameterLimit
      : 1000
    var parse = parser('qs')
  
    if (isNaN(parameterLimit) || parameterLimit < 1) {
      throw new TypeError('option parameterLimit must be a positive number')
    }
  
    if (isFinite(parameterLimit)) {
      parameterLimit = parameterLimit | 0
    }
  
    return function queryparse (body) {
      var paramCount = parameterCount(body, parameterLimit)
  
      if (paramCount === undefined) {
        debug('too many parameters')
        throw createError(413, 'too many parameters', {
          type: 'parameters.too.many'
        })
      }
  
      var arrayLimit = Math.max(100, paramCount)
  
      debug('parse extended urlencoding')
      return parse(body, {
        allowPrototypes: true,
        arrayLimit: arrayLimit,
        depth: Infinity,
        parameterLimit: parameterLimit
      })
    }
  }
  
  /**
   * Get the charset of a request.
   *
   * @param {object} req
   * @api private
   */
  
  function getCharset (req) {
    try {
      return (contentType.parse(req).parameters.charset || '').toLowerCase()
    } catch (e) {
      return undefined
    }
  }
  
  /**
   * Count the number of parameters, stopping once limit reached
   *
   * @param {string} body
   * @param {number} limit
   * @api private
   */
  
  function parameterCount (body, limit) {
    var count = 0
    var index = 0
  
    while ((index = body.indexOf('&', index)) !== -1) {
      count++
      index++
  
      if (count === limit) {
        return undefined
      }
    }
  
    return count
  }
  
  /**
   * Get parser for module name dynamically.
   *
   * @param {string} name
   * @return {function}
   * @api private
   */
  
  function parser (name) {
    var mod = parsers[name]
  
    if (mod !== undefined) {
      return mod.parse
    }
  
    // this uses a switch for static require analysis
    switch (name) {
      case 'qs':
        mod = require('qs')
        break
      case 'querystring':
        mod = require('querystring')
        break
    }
  
    // store to prevent invoking require()
    parsers[name] = mod
  
    return mod.parse
  }
  
  /**
   * Get the simple query parser.
   *
   * @param {object} options
   */
  
  function simpleparser (options) {
    var parameterLimit = options.parameterLimit !== undefined
      ? options.parameterLimit
      : 1000
    var parse = parser('querystring')
  
    if (isNaN(parameterLimit) || parameterLimit < 1) {
      throw new TypeError('option parameterLimit must be a positive number')
    }
  
    if (isFinite(parameterLimit)) {
      parameterLimit = parameterLimit | 0
    }
  
    return function queryparse (body) {
      var paramCount = parameterCount(body, parameterLimit)
  
      if (paramCount === undefined) {
        debug('too many parameters')
        throw createError(413, 'too many parameters', {
          type: 'parameters.too.many'
        })
      }
  
      debug('parse urlencoding')
      return parse(body, undefined, undefined, {maxKeys: parameterLimit})
    }
  }
  
  /**
   * Get the simple type checker.
   *
   * @param {string} type
   * @return {function}
   */
  
  function typeChecker (type) {
    return function checkType (req) {
      return Boolean(typeis(req, type))
    }
  }
  