whole_func_string: function fetchVersions (options, nameVersion) {
      // console.log(nameVersion);
      // TODO use check.schema
    check.verify.object(nameVersion, 'expected name, version object')
    var name = nameVersion.name
    var version = nameVersion.version
    check.verify.string(name, 'missing name string')
    check.verify.string(version, 'missing version string')
  
    var cleanVersionForName = _.partial(cleanVersionFor, name)
    function isLaterVersion (ver) {
      var later = semver.gt(ver, version)
      return later
    }
  
      // console.log('fetching versions for', name, 'current version', version);
    var MAX_WAIT_TIMEOUT = options.checkVersionTimeout || 25000
    var deferred = q.defer()
  
    function rejectOnTimeout () {
      var msg = 'timed out waiting for NPM for package ' + name +
              ' after ' + MAX_WAIT_TIMEOUT + 'ms'
      console.error(msg)
      deferred.reject(msg)
    }
  
    function escapeName (str) {
      return str.replace('/', '%2F')
    }
  
    registryUrl().then(function (npmUrl) {
      log('NPM registry url', npmUrl)
      la(check.webUrl(npmUrl), 'need npm registry url, got', npmUrl)
  
      npmUrl = npmUrl.replace(/^https:/, 'http:').trim()
      var url = (options.registry || npmUrl) + escapeName(name)
  
          // TODO how to detect if the registry is not responding?
  
      log('getting url', url)
      request.get(url, onNPMversions)
      var timer = setTimeout(rejectOnTimeout, MAX_WAIT_TIMEOUT)
  
      function onNPMversions (err, response, body) {
        log('got response for', url)
        clearTimeout(timer)
  
        if (err) {
          console.error('ERROR when fetching info for package', name)
          deferred.reject(err.message)
          return
        }
  
        if (is404(response)) {
          log('404 response for', url)
          deferred.resolve({
            name: name,
            versions: []
          })
          return
        }
  
        try {
          log('parsing response body')
          var info = JSON.parse(body)
          log('parsed response, error?', info.error)
          if (info.error) {
            log('error parsing\n' + body + '\n')
            var str = formNpmErrorMessage(name, info)
            console.error(str)
  
            if (isNotFound(info.error)) {
              deferred.resolve({
                name: name,
                versions: []
              })
              return
            }
  
            deferred.reject(str)
            return
          }
          log('extracting versions')
          var versions = extractVersions(info)
          log('%d versions', versions.length)
  
          if (!Array.isArray(versions)) {
            throw new Error('Could not get versions for ' + name +
                          ' from ' + JSON.stringify(info) +
                          ' response ' + JSON.stringify(response, null, 2))
          }
  
          var validVersions = versions.filter(cleanVersionForName)
          var newerVersions = validVersions.filter(isLaterVersion)
          log('%d valid versions', validVersions.length)
          if (validVersions.length) {
            log('last version %s', R.last(validVersions))
          }
          if (newerVersions.length) {
            log('%d newer versions', newerVersions.length)
            log('from %s to %s', R.head(newerVersions), R.last(newerVersions))
          }
  
          deferred.resolve({
            name: name,
            versions: newerVersions
          })
          return
        } catch (err) {
          console.error(err)
          deferred.reject('Could not fetch versions for ' + name)
        }
      }
    })
  
    return deferred.promise
  }
func_code_string: function fetchVersions (options, nameVersion) {
      // console.log(nameVersion);
      // TODO use check.schema
    check.verify.object(nameVersion, 'expected name, version object')
    var name = nameVersion.name
    var version = nameVersion.version
    check.verify.string(name, 'missing name string')
    check.verify.string(version, 'missing version string')
  
    var cleanVersionForName = _.partial(cleanVersionFor, name)
    function isLaterVersion (ver) {
      var later = semver.gt(ver, version)
      return later
    }
  
      // console.log('fetching versions for', name, 'current version', version);
    var MAX_WAIT_TIMEOUT = options.checkVersionTimeout || 25000
    var deferred = q.defer()
  
    function rejectOnTimeout () {
      var msg = 'timed out waiting for NPM for package ' + name +
              ' after ' + MAX_WAIT_TIMEOUT + 'ms'
      console.error(msg)
      deferred.reject(msg)
    }
  
    function escapeName (str) {
      return str.replace('/', '%2F')
    }
  
    registryUrl().then(function (npmUrl) {
      log('NPM registry url', npmUrl)
      la(check.webUrl(npmUrl), 'need npm registry url, got', npmUrl)
  
      npmUrl = npmUrl.replace(/^https:/, 'http:').trim()
      var url = (options.registry || npmUrl) + escapeName(name)
  
          // TODO how to detect if the registry is not responding?
  
      log('getting url', url)
      request.get(url, onNPMversions)
      var timer = setTimeout(rejectOnTimeout, MAX_WAIT_TIMEOUT)
  
      function onNPMversions (err, response, body) {
        log('got response for', url)
        clearTimeout(timer)
  
        if (err) {
          console.error('ERROR when fetching info for package', name)
          deferred.reject(err.message)
          return
        }
  
        if (is404(response)) {
          log('404 response for', url)
          deferred.resolve({
            name: name,
            versions: []
          })
          return
        }
  
        try {
          log('parsing response body')
          var info = JSON.parse(body)
          log('parsed response, error?', info.error)
          if (info.error) {
            log('error parsing\n' + body + '\n')
            var str = formNpmErrorMessage(name, info)
            console.error(str)
  
            if (isNotFound(info.error)) {
              deferred.resolve({
                name: name,
                versions: []
              })
              return
            }
  
            deferred.reject(str)
            return
          }
          log('extracting versions')
          var versions = extractVersions(info)
          log('%d versions', versions.length)
  
          if (!Array.isArray(versions)) {
            throw new Error('Could not get versions for ' + name +
                          ' from ' + JSON.stringify(info) +
                          ' response ' + JSON.stringify(response, null, 2))
          }
  
          var validVersions = versions.filter(cleanVersionForName)
          var newerVersions = validVersions.filter(isLaterVersion)
          log('%d valid versions', validVersions.length)
          if (validVersions.length) {
            log('last version %s', R.last(validVersions))
          }
          if (newerVersions.length) {
            log('%d newer versions', newerVersions.length)
            log('from %s to %s', R.head(newerVersions), R.last(newerVersions))
          }
  
          deferred.resolve({
            name: name,
            versions: newerVersions
          })
          return
        } catch (err) {
          console.error(err)
          deferred.reject('Could not fetch versions for ' + name)
        }
      }
    })
  
    return deferred.promise
  }
func_documentation_string: fetching versions inspired by https://github.com/jprichardson/npm-latest returns a promise