void processEvents() {
		while (active) {

			// wait for key to be signalled
			final WatchKey key;
			try {
				key = watcher.take();
			} catch (Exception ignore) {
				return;
			}

			final Path dir = keys.get(key);
			if (dir == null) {
				LOG.error("WatchKey not recognized! {} does not exist in {}", key, keys);
				continue;
			}

			for (final WatchEvent<?> event : key.pollEvents()) {
				final WatchEvent.Kind kind = event.kind();

				// TBD - provide example of how OVERFLOW event is handled
				if (kind == StandardWatchEventKinds.OVERFLOW) {
					continue;
				}

				// Context for directory entry event is the file name of entry
				@SuppressWarnings({"unchecked", "SuppressionAnnotation"}) final WatchEvent<Path> ev = (WatchEvent<Path>) (event);
				final Path name = ev.context();
				final Path child = dir.resolve(name);

				LOG.info("{}: {}", event.kind().name(), child);

				created(child);
			}

			// reset key and remove from set if directory no longer accessible
			final boolean invalid = !key.reset();
			if (invalid) {
				keys.remove(key);

				// all directories are inaccessible
				if (keys.isEmpty()) {
					break;
				}
			}
		}
	}