'use strict';

var path     = require('path')
  , memoize  = require('es5-ext/lib/Function/prototype/memoize')
  , callable = require('es5-ext/lib/Object/valid-callable')
  , deferred = require('deferred')
  , ee       = require('event-emitter')

  , resolve = path.resolve, dirname = path.dirname;

var findRoot = memoize.call(function (isRoot, path) {
	var listeners = {}, onvalue, onevent, deferral, promise;

	deferral = deferred();
	promise = ee(deferral.promise);

	onvalue = function (value) {
		var dir;
		isRoot(this).on('change', listeners[this] = onevent);
		if (value) {
			return this;
		}
		dir = dirname(this);
		if (dir != this) {
			return isRoot(dir)(onvalue.bind(dir));
		} else {
			return null;
		}
	};

	onevent = function (value, path) {
		var dir;
		if (!value) {
			dir = dirname(path);
			if (dir !== path) {
				isRoot(dir)(onvalue.bind(dir)).end(function (path) {
					promise._base.value = path;
					promise.emit('change', path);
				}, null);
			} else {
					promise._base.value = null;
				promise.emit('change', null);
			}
		} else {
			dir = dirname(path);
			while (listeners[dir]) {
				isRoot(dir).off('change', onevent);
				delete listeners[dir];
				dir = dirname(dir);
			}
			promise._base.value = path;
			promise.emit('change', path);
		}
	};

	deferral.resolve(isRoot(path)(onvalue.bind(path)));
	return promise;
});

module.exports = function (isRoot, path) {
	return findRoot(callable(isRoot),
		dirname(resolve(String(path)))).cb(arguments[2]);
};

@@ -389,21 +389,16 @@
 ent, def
-erral
 , promis
@@ -398,28 +398,30 @@
  promise
+, known
 ;%0A%0A%09def
-erral
  = defer
@@ -444,21 +444,16 @@
 = ee(def
-erral
 .promise
@@ -497,16 +497,52 @@
 ar dir;%0A
+%09%09if (known) %7B%0A%09%09%09return false;%0A%09%09%7D%0A
 %09%09isRoot
@@ -600,24 +600,41 @@
 f (value) %7B%0A
+%09%09%09known = true;%0A
 %09%09%09return th
@@ -738,16 +738,33 @@
  else %7B%0A
+%09%09%09known = true;%0A
 %09%09%09retur
@@ -886,24 +886,43 @@
 !== path) %7B%0A
+%09%09%09%09known = false;%0A
 %09%09%09%09isRoot(d
@@ -962,24 +962,72 @@
 on (path) %7B%0A
+%09%09%09%09%09if (path === false) %7B%0A%09%09%09%09%09%09return;%0A%09%09%09%09%09%7D%0A
 %09%09%09%09%09promise
@@ -1108,25 +1108,24 @@
  else %7B%0A%09%09%09%09
-%09
 promise._bas
@@ -1190,16 +1190,33 @@
  else %7B%0A
+%09%09%09known = true;%0A
 %09%09%09dir =
@@ -1355,16 +1355,56 @@
 );%0A%09%09%09%7D%0A
+%09%09%09if (promise._base.value !== path) %7B%0A%09
 %09%09%09promi
@@ -1426,16 +1426,17 @@
 = path;%0A
+%09
 %09%09%09promi
@@ -1460,16 +1460,21 @@
  path);%0A
+%09%09%09%7D%0A
 %09%09%7D%0A%09%7D;%0A
@@ -1482,13 +1482,8 @@
 %09def
-erral
 .res

Handle concurrent events. Do not emit false positives