text: // A thing that emits "entry" events with Reader objects
  // Pausing it causes it to stop emitting entry events, and also
  // pauses the current entry if there is one.
  
  module.exports = DirReader
  
  var fs = require('graceful-fs')
  var inherits = require('inherits')
  var path = require('path')
  var Reader = require('./reader.js')
  var assert = require('assert').ok
  
  inherits(DirReader, Reader)
  
  function DirReader (props) {
    var self = this
    if (!(self instanceof DirReader)) {
      throw new Error('DirReader must be called as constructor.')
    }
  
    // should already be established as a Directory type
    if (props.type !== 'Directory' || !props.Directory) {
      throw new Error('Non-directory type ' + props.type)
    }
  
    self.entries = null
    self._index = -1
    self._paused = false
    self._length = -1
  
    if (props.sort) {
      this.sort = props.sort
    }
  
    Reader.call(this, props)
  }
  
  DirReader.prototype._getEntries = function () {
    var self = this
  
    // race condition.  might pause() before calling _getEntries,
    // and then resume, and try to get them a second time.
    if (self._gotEntries) return
    self._gotEntries = true
  
    fs.readdir(self._path, function (er, entries) {
      if (er) return self.error(er)
  
      self.entries = entries
  
      self.emit('entries', entries)
      if (self._paused) self.once('resume', processEntries)
      else processEntries()
  
      function processEntries () {
        self._length = self.entries.length
        if (typeof self.sort === 'function') {
          self.entries = self.entries.sort(self.sort.bind(self))
        }
        self._read()
      }
    })
  }
  
  // start walking the dir, and emit an "entry" event for each one.
  DirReader.prototype._read = function () {
    var self = this
  
    if (!self.entries) return self._getEntries()
  
    if (self._paused || self._currentEntry || self._aborted) {
      // console.error('DR paused=%j, current=%j, aborted=%j', self._paused, !!self._currentEntry, self._aborted)
      return
    }
  
    self._index++
    if (self._index >= self.entries.length) {
      if (!self._ended) {
        self._ended = true
        self.emit('end')
        self.emit('close')
      }
      return
    }
  
    // ok, handle this one, then.
  
    // save creating a proxy, by stat'ing the thing now.
    var p = path.resolve(self._path, self.entries[self._index])
    assert(p !== self._path)
    assert(self.entries[self._index])
  
    // set this to prevent trying to _read() again in the stat time.
    self._currentEntry = p
    fs[ self.props.follow ? 'stat' : 'lstat' ](p, function (er, stat) {
      if (er) return self.error(er)
  
      var who = self._proxy || self
  
      stat.path = p
      stat.basename = path.basename(p)
      stat.dirname = path.dirname(p)
      var childProps = self.getChildProps.call(who, stat)
      childProps.path = p
      childProps.basename = path.basename(p)
      childProps.dirname = path.dirname(p)
  
      var entry = Reader(childProps, stat)
  
      // console.error("DR Entry", p, stat.size)
  
      self._currentEntry = entry
  
      // "entry" events are for direct entries in a specific dir.
      // "child" events are for any and all children at all levels.
      // This nomenclature is not completely final.
  
      entry.on('pause', function (who) {
        if (!self._paused && !entry._disowned) {
          self.pause(who)
        }
      })
  
      entry.on('resume', function (who) {
        if (self._paused && !entry._disowned) {
          self.resume(who)
        }
      })
  
      entry.on('stat', function (props) {
        self.emit('_entryStat', entry, props)
        if (entry._aborted) return
        if (entry._paused) {
          entry.once('resume', function () {
            self.emit('entryStat', entry, props)
          })
        } else self.emit('entryStat', entry, props)
      })
  
      entry.on('ready', function EMITCHILD () {
        // console.error("DR emit child", entry._path)
        if (self._paused) {
          // console.error("  DR emit child - try again later")
          // pause the child, and emit the "entry" event once we drain.
          // console.error("DR pausing child entry")
          entry.pause(self)
          return self.once('resume', EMITCHILD)
        }
  
        // skip over sockets.  they can't be piped around properly,
        // so there's really no sense even acknowledging them.
        // if someone really wants to see them, they can listen to
        // the "socket" events.
        if (entry.type === 'Socket') {
          self.emit('socket', entry)
        } else {
          self.emitEntry(entry)
        }
      })
  
      var ended = false
      entry.on('close', onend)
      entry.on('disown', onend)
      function onend () {
        if (ended) return
        ended = true
        self.emit('childEnd', entry)
        self.emit('entryEnd', entry)
        self._currentEntry = null
        if (!self._paused) {
          self._read()
        }
      }
  
      // XXX Remove this.  Works in node as of 0.6.2 or so.
      // Long filenames should not break stuff.
      entry.on('error', function (er) {
        if (entry._swallowErrors) {
          self.warn(er)
          entry.emit('end')
          entry.emit('close')
        } else {
          self.emit('error', er)
        }
      })
  
      // proxy up some events.
      ;[
        'child',
        'childEnd',
        'warn'
      ].forEach(function (ev) {
        entry.on(ev, self.emit.bind(self, ev))
      })
    })
  }
  
  DirReader.prototype.disown = function (entry) {
    entry.emit('beforeDisown')
    entry._disowned = true
    entry.parent = entry.root = null
    if (entry === this._currentEntry) {
      this._currentEntry = null
    }
    entry.emit('disown')
  }
  
  DirReader.prototype.getChildProps = function () {
    return {
      depth: this.depth + 1,
      root: this.root || this,
      parent: this,
      follow: this.follow,
      filter: this.filter,
      sort: this.props.sort,
      hardlinks: this.props.hardlinks
    }
  }
  
  DirReader.prototype.pause = function (who) {
    var self = this
    if (self._paused) return
    who = who || self
    self._paused = true
    if (self._currentEntry && self._currentEntry.pause) {
      self._currentEntry.pause(who)
    }
    self.emit('pause', who)
  }
  
  DirReader.prototype.resume = function (who) {
    var self = this
    if (!self._paused) return
    who = who || self
  
    self._paused = false
    // console.error('DR Emit Resume', self._path)
    self.emit('resume', who)
    if (self._paused) {
      // console.error('DR Re-paused', self._path)
      return
    }
  
    if (self._currentEntry) {
      if (self._currentEntry.resume) self._currentEntry.resume(who)
    } else self._read()
  }
  
  DirReader.prototype.emitEntry = function (entry) {
    this.emit('entry', entry)
    this.emit('child', entry)
  }
  