@Override
    public WatchKey register(final Watchable folder,
                             final WatchEvent.Kind<?>[] events,
                             final WatchEvent.Modifier... modifiers)
        throws IOException {
        if(log.isInfoEnabled()) {
            log.info(String.format("Register file %s for events %s", folder, Arrays.toString(events)));
        }
        final Pointer[] values = {
            CFStringRef.toCFString(folder.toString()).getPointer()};

        final MacOSXWatchKey key = new MacOSXWatchKey(folder, this, events);

        final double latency = 1.0; // Latency in seconds

        final Map<File, Long> timestamps = createLastModifiedMap(new File(folder.toString()));
        final FSEvents.FSEventStreamCallback callback = new Callback(key, timestamps);
        final FSEventStreamRef stream = library.FSEventStreamCreate(
            Pointer.NULL, callback, Pointer.NULL,
            library.CFArrayCreate(null, values, CFIndex.valueOf(1), null),
            -1, latency,
            kFSEventStreamCreateFlagNoDefer);
        final CountDownLatch lock = new CountDownLatch(1);
        final CFRunLoop loop = new CFRunLoop(lock, stream);
        threadFactory.newThread(loop).start();
        Uninterruptibles.awaitUninterruptibly(lock);
        loops.put(key, loop);
        callbacks.put(key, callback);
        return key;
    }
@Test
    @Ignore
    public void testListener() throws Exception {
        final FileWatcher watcher = new FileWatcher(new FSEventWatchService());
        final Local file = LocalFactory.get(LocalFactory.get(System.getProperty("java.io.tmpdir")), String.format("é%s", new AlphanumericRandomStringService().random()));
        final CountDownLatch update = new CountDownLatch(1);
        final CountDownLatch delete = new CountDownLatch(1);
        final FileWatcherListener listener = new DisabledFileWatcherListener() {
            @Override
            public void fileWritten(final Local file) {
                try {
                    assertEquals(new File(file.getAbsolute()).getCanonicalPath(), new File(file.getAbsolute()).getCanonicalPath());
                }
                catch(IOException e) {
                    fail();
                }
                update.countDown();
            }

            @Override
            public void fileDeleted(final Local file) {
                try {
                    assertEquals(new File(file.getAbsolute()).getCanonicalPath(), new File(file.getAbsolute()).getCanonicalPath());
                }
                catch(IOException e) {
                    fail();
                }
                delete.countDown();
            }
        };
        LocalTouchFactory.get().touch(file);
        assertTrue(file.exists());
        assertTrue(watcher.register(file.getParent(), new FileWatcher.DefaultFileFilter(file), listener).await(1, TimeUnit.SECONDS));
        final ProcessBuilder sh = new ProcessBuilder("sh", "-c", String.format("echo 'Test' >> %s", file.getAbsolute()));
        final Process cat = sh.start();
        assertTrue(cat.waitFor(5L, TimeUnit.SECONDS));
        assertTrue(update.await(5L, TimeUnit.SECONDS));
        file.delete();
        assertTrue(delete.await(5L, TimeUnit.SECONDS));
        watcher.close();
    }