text: 'use strict';
  
  var fs = require('fs');
  var sysPath = require('path');
  var readdirp = require('readdirp');
  var fsevents;
  try {
    fsevents = require('fsevents');
  } catch (error) {}
  
  // fsevents instance helper functions
  
  // object to hold per-process fsevents instances
  // (may be shared across chokidar FSWatcher instances)
  var FSEventsWatchers = Object.create(null);
  
  // Private function: Instantiates the fsevents interface
  
  // * path       - string, path to be watched
  // * callback   - function, called when fsevents is bound and ready
  
  // Returns new fsevents instance
  function createFSEventsInstance(path, callback) {
    return new fsevents(path).on('fsevent', callback).start();
  }
  
  // Private function: Instantiates the fsevents interface or binds listeners
  // to an existing one covering the same file tree
  
  // * path       - string, path to be watched
  // * realPath   - string, real path (in case of symlinks)
  // * listener   - function, called when fsevents emits events
  // * rawEmitter - function, passes data to listeners of the 'raw' event
  
  // Returns close function
  function setFSEventsListener(path, realPath, listener, rawEmitter) {
    var watchPath = sysPath.extname(path) ? sysPath.dirname(path) : path;
    var watchContainer;
  
    var resolvedPath = sysPath.resolve(path);
    var hasSymlink = resolvedPath !== realPath;
    function filteredListener(fullPath, flags, info) {
      if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath);
      if (fullPath === resolvedPath || !fullPath.indexOf(resolvedPath + sysPath.sep)) listener(fullPath, flags, info);
    }
  
    // check if there is already a watcher on a parent path
    // modifies `watchPath` to the parent path when it finds a match
    function watchedParent() {
      return Object.keys(FSEventsWatchers).some(function (watchedPath) {
        // condition is met when indexOf returns 0
        if (!realPath.indexOf(sysPath.resolve(watchedPath) + sysPath.sep)) {
          watchPath = watchedPath;
          return true;
        }
      });
    }
  
    if (watchPath in FSEventsWatchers || watchedParent()) {
      watchContainer = FSEventsWatchers[watchPath];
      watchContainer.listeners.push(filteredListener);
    } else {
      watchContainer = FSEventsWatchers[watchPath] = {
        listeners: [filteredListener],
        rawEmitters: [rawEmitter],
        watcher: createFSEventsInstance(watchPath, function (fullPath, flags) {
          var info = fsevents.getInfo(fullPath, flags);
          watchContainer.listeners.forEach(function (listener) {
            listener(fullPath, flags, info);
          });
          watchContainer.rawEmitters.forEach(function (emitter) {
            emitter(info.event, fullPath, info);
          });
        })
      };
    }
    var listenerIndex = watchContainer.listeners.length - 1;
  
    // removes this instance's listeners and closes the underlying fsevents
    // instance if there are no more listeners left
    return function close() {
      delete watchContainer.listeners[listenerIndex];
      delete watchContainer.rawEmitters[listenerIndex];
      if (!Object.keys(watchContainer.listeners).length) {
        watchContainer.watcher.stop();
        delete FSEventsWatchers[watchPath];
      }
    };
  }
  
  // returns boolean indicating whether fsevents can be used
  function canUse() {
    return fsevents && Object.keys(FSEventsWatchers).length < 128;
  }
  
  // determines subdirectory traversal levels from root to path
  function depth(path, root) {
    var i = 0;
    while (!path.indexOf(root) && (path = sysPath.dirname(path)) !== root) i++;
    return i;
  }
  
  // fake constructor for attaching fsevents-specific prototype methods that
  // will be copied to FSWatcher's prototype
  function FsEventsHandler() {}
  
  // Private method: Handle symlinks encountered during directory scan
  
  // * wathPath   - string, file/dir path to be watched with fsevents
  // * realPath   - string, real path (in case of symlinks)
  // * transform  - function, path transformer
  // * globFilter - function, path filter in case a glob pattern was provided
  
  // Returns close function for the watcher instance
  FsEventsHandler.prototype._watchWithFsEvents = function (watchPath, realPath, transform, globFilter) {
    if (this._isIgnored(watchPath)) return;
    var watchCallback = (function (fullPath, flags, info) {
      if (this.options.depth !== undefined && depth(fullPath, realPath) > this.options.depth) return;
      var path = transform(sysPath.join(watchPath, sysPath.relative(watchPath, fullPath)));
      if (globFilter && !globFilter(path)) return;
      // ensure directories are tracked
      var parent = sysPath.dirname(path);
      var item = sysPath.basename(path);
      var watchedDir = this._getWatchedDir(info.type === 'directory' ? path : parent);
      var checkIgnored = (function (stats) {
        if (this._isIgnored(path, stats)) {
          this._ignoredPaths[path] = true;
          if (stats && stats.isDirectory()) {
            this._ignoredPaths[path + '/**/*'] = true;
          }
          return true;
        } else {
          delete this._ignoredPaths[path];
          delete this._ignoredPaths[path + '/**/*'];
        }
      }).bind(this);
  
      var handleEvent = (function (event) {
        if (checkIgnored()) return;
  
        if (event === 'unlink') {
          // suppress unlink events on never before seen files
          if (info.type === 'directory' || watchedDir.has(item)) {
            this._remove(parent, item);
          }
        } else {
          if (event === 'add') {
            // track new directories
            if (info.type === 'directory') this._getWatchedDir(path);
  
            if (info.type === 'symlink' && this.options.followSymlinks) {
              // push symlinks back to the top of the stack to get handled
              var curDepth = this.options.depth === undefined ? undefined : depth(fullPath, realPath) + 1;
              return this._addToFsEvents(path, false, true, curDepth);
            } else {
              // track new paths
              // (other than symlinks being followed, which will be tracked soon)
              this._getWatchedDir(parent).add(item);
            }
          }
          var eventName = info.type === 'directory' ? event + 'Dir' : event;
          this._emit(eventName, path);
        }
      }).bind(this);
  
      function addOrChange() {
        handleEvent(watchedDir.has(item) ? 'change' : 'add');
      }
      function checkFd() {
        fs.open(path, 'r', function (error, fd) {
          if (fd) fs.close(fd);
          error && error.code !== 'EACCES' ? handleEvent('unlink') : addOrChange();
        });
      }
      // correct for wrong events emitted
      var wrongEventFlags = [69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912];
      if (wrongEventFlags.indexOf(flags) !== -1 || info.event === 'unknown') {
        if (typeof this.options.ignored === 'function') {
          fs.stat(path, function (error, stats) {
            if (checkIgnored(stats)) return;
            stats ? addOrChange() : handleEvent('unlink');
          });
        } else {
          checkFd();
        }
      } else {
        switch (info.event) {
          case 'created':
          case 'modified':
            return addOrChange();
          case 'deleted':
          case 'moved':
            return checkFd();
        }
      }
    }).bind(this);
  
    var closer = setFSEventsListener(watchPath, realPath, watchCallback, this.emit.bind(this, 'raw'));
  
    this._emitReady();
    return closer;
  };
  
  // Private method: Handle symlinks encountered during directory scan
  
  // * linkPath   - string, path to symlink
  // * fullPath   - string, absolute path to the symlink
  // * transform  - function, pre-existing path transformer
  // * curDepth   - int, level of subdirectories traversed to where symlink is
  
  // Returns nothing
  FsEventsHandler.prototype._fsEventsSymlink = function (linkPath, fullPath, transform, curDepth) {
    // don't follow the same symlink more than once
    if (this._symlinkPaths[fullPath]) return;else this._symlinkPaths[fullPath] = true;
  
    this._readyCount++;
  
    fs.realpath(linkPath, (function (error, linkTarget) {
      if (this._handleError(error) || this._isIgnored(linkTarget)) {
        return this._emitReady();
      }
  
      this._readyCount++;
  
      // add the linkTarget for watching with a wrapper for transform
      // that causes emitted paths to incorporate the link's path
      this._addToFsEvents(linkTarget || linkPath, function (path) {
        var dotSlash = '.' + sysPath.sep;
        var aliasedPath = linkPath;
        if (linkTarget && linkTarget !== dotSlash) {
          aliasedPath = path.replace(linkTarget, linkPath);
        } else if (path !== dotSlash) {
          aliasedPath = sysPath.join(linkPath, path);
        }
        return transform(aliasedPath);
      }, false, curDepth);
    }).bind(this));
  };
  
  // Private method: Handle added path with fsevents
  
  // * path       - string, file/directory path or glob pattern
  // * transform  - function, converts working path to what the user expects
  // * forceAdd   - boolean, ensure add is emitted
  // * priorDepth - int, level of subdirectories already traversed
  
  // Returns nothing
  FsEventsHandler.prototype._addToFsEvents = function (path, transform, forceAdd, priorDepth) {
  
    // applies transform if provided, otherwise returns same value
    var processPath = typeof transform === 'function' ? transform : function (val) {
      return val;
    };
  
    var emitAdd = (function (newPath, stats) {
      var pp = processPath(newPath);
      var isDir = stats.isDirectory();
      var dirObj = this._getWatchedDir(sysPath.dirname(pp));
      var base = sysPath.basename(pp);
  
      // ensure empty dirs get tracked
      if (isDir) this._getWatchedDir(pp);
  
      if (dirObj.has(base)) return;
      dirObj.add(base);
  
      if (!this.options.ignoreInitial || forceAdd === true) {
        this._emit(isDir ? 'addDir' : 'add', pp, stats);
      }
    }).bind(this);
  
    var wh = this._getWatchHelpers(path);
  
    // evaluate what is at the path we're being asked to watch
    fs[wh.statMethod](wh.watchPath, (function (error, stats) {
      if (this._handleError(error) || this._isIgnored(wh.watchPath, stats)) {
        this._emitReady();
        return this._emitReady();
      }
  
      if (stats.isDirectory()) {
        // emit addDir unless this is a glob parent
        if (!wh.globFilter) emitAdd(processPath(path), stats);
  
        // don't recurse further if it would exceed depth setting
        if (priorDepth && priorDepth > this.options.depth) return;
  
        // scan the contents of the dir
        readdirp({
          root: wh.watchPath,
          entryType: 'all',
          fileFilter: wh.filterPath,
          directoryFilter: wh.filterDir,
          lstat: true,
          depth: this.options.depth - (priorDepth || 0)
        }).on('data', (function (entry) {
          // need to check filterPath on dirs b/c filterDir is less restrictive
          if (entry.stat.isDirectory() && !wh.filterPath(entry)) return;
  
          var joinedPath = sysPath.join(wh.watchPath, entry.path);
          var fullPath = entry.fullPath;
  
          if (wh.followSymlinks && entry.stat.isSymbolicLink()) {
            // preserve the current depth here since it can't be derived from
            // real paths past the symlink
            var curDepth = this.options.depth === undefined ? undefined : depth(joinedPath, sysPath.resolve(wh.watchPath)) + 1;
  
            this._fsEventsSymlink(joinedPath, fullPath, processPath, curDepth);
          } else {
            emitAdd(joinedPath, entry.stat);
          }
        }).bind(this)).on('end', this._emitReady);
      } else {
        emitAdd(wh.watchPath, stats);
        this._emitReady();
      }
    }).bind(this));
  
    if (this.options.persistent) {
      var initWatch = (function (error, realPath) {
        var closer = this._watchWithFsEvents(wh.watchPath, sysPath.resolve(realPath || wh.watchPath), processPath, wh.globFilter);
        if (closer) this._closers[path] = closer;
      }).bind(this);
  
      if (typeof transform === 'function') {
        // realpath has already been resolved
        initWatch();
      } else {
        fs.realpath(wh.watchPath, initWatch);
      }
    }
  };
  
  module.exports = FsEventsHandler;
  module.exports.canUse = canUse;
  
  //# sourceMappingURL=fsevents-handler-compiled.js.map