http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fen.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fen.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fen.go
new file mode 100644
index 0000000..ced39cb
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fen.go
@@ -0,0 +1,37 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package fsnotify
+
+import (
+       "errors"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+       Events chan Event
+       Errors chan error
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins 
waiting for events.
+func NewWatcher() (*Watcher, error) {
+       return nil, errors.New("FEN based watcher not yet supported for 
fsnotify\n")
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+       return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+       return nil
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+       return nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fsnotify.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fsnotify.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fsnotify.go
new file mode 100644
index 0000000..d1d39a0
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/fsnotify.go
@@ -0,0 +1,62 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+// Package fsnotify provides a platform-independent interface for file system 
notifications.
+package fsnotify
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// Event represents a single file system notification.
+type Event struct {
+       Name string // Relative path to the file or directory.
+       Op   Op     // File operation that triggered the event.
+}
+
+// Op describes a set of file operations.
+type Op uint32
+
+// These are the generalized file operations that can trigger a notification.
+const (
+       Create Op = 1 << iota
+       Write
+       Remove
+       Rename
+       Chmod
+)
+
+// String returns a string representation of the event in the form
+// "file: REMOVE|WRITE|..."
+func (e Event) String() string {
+       // Use a buffer for efficient string concatenation
+       var buffer bytes.Buffer
+
+       if e.Op&Create == Create {
+               buffer.WriteString("|CREATE")
+       }
+       if e.Op&Remove == Remove {
+               buffer.WriteString("|REMOVE")
+       }
+       if e.Op&Write == Write {
+               buffer.WriteString("|WRITE")
+       }
+       if e.Op&Rename == Rename {
+               buffer.WriteString("|RENAME")
+       }
+       if e.Op&Chmod == Chmod {
+               buffer.WriteString("|CHMOD")
+       }
+
+       // If buffer remains empty, return no event names
+       if buffer.Len() == 0 {
+               return fmt.Sprintf("%q: ", e.Name)
+       }
+
+       // Return a list of event names, with leading pipe character stripped
+       return fmt.Sprintf("%q: %s", e.Name, buffer.String()[1:])
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify.go
new file mode 100644
index 0000000..9700df5
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify.go
@@ -0,0 +1,325 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+       "errors"
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+       "strings"
+       "sync"
+       "unsafe"
+
+       "golang.org/x/sys/unix"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+       Events   chan Event
+       Errors   chan error
+       mu       sync.Mutex // Map access
+       cv       *sync.Cond // sync removing on rm_watch with IN_IGNORE
+       fd       int
+       poller   *fdPoller
+       watches  map[string]*watch // Map of inotify watches (key: path)
+       paths    map[int]string    // Map of watched paths (key: watch 
descriptor)
+       done     chan struct{}     // Channel for sending a "quit message" to 
the reader goroutine
+       doneResp chan struct{}     // Channel to respond to Close
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins 
waiting for events.
+func NewWatcher() (*Watcher, error) {
+       // Create inotify fd
+       fd, errno := unix.InotifyInit()
+       if fd == -1 {
+               return nil, errno
+       }
+       // Create epoll
+       poller, err := newFdPoller(fd)
+       if err != nil {
+               unix.Close(fd)
+               return nil, err
+       }
+       w := &Watcher{
+               fd:       fd,
+               poller:   poller,
+               watches:  make(map[string]*watch),
+               paths:    make(map[int]string),
+               Events:   make(chan Event),
+               Errors:   make(chan error),
+               done:     make(chan struct{}),
+               doneResp: make(chan struct{}),
+       }
+       w.cv = sync.NewCond(&w.mu)
+
+       go w.readEvents()
+       return w, nil
+}
+
+func (w *Watcher) isClosed() bool {
+       select {
+       case <-w.done:
+               return true
+       default:
+               return false
+       }
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+       if w.isClosed() {
+               return nil
+       }
+
+       // Send 'close' signal to goroutine, and set the Watcher to closed.
+       close(w.done)
+
+       // Wake up goroutine
+       w.poller.wake()
+
+       // Wait for goroutine to close
+       <-w.doneResp
+
+       return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+       name = filepath.Clean(name)
+       if w.isClosed() {
+               return errors.New("inotify instance already closed")
+       }
+
+       const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
+               unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
+               unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
+
+       var flags uint32 = agnosticEvents
+
+       w.mu.Lock()
+       watchEntry, found := w.watches[name]
+       w.mu.Unlock()
+       if found {
+               watchEntry.flags |= flags
+               flags |= unix.IN_MASK_ADD
+       }
+       wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
+       if wd == -1 {
+               return errno
+       }
+
+       w.mu.Lock()
+       w.watches[name] = &watch{wd: uint32(wd), flags: flags}
+       w.paths[wd] = name
+       w.mu.Unlock()
+
+       return nil
+}
+
+// Remove stops watching the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+       name = filepath.Clean(name)
+
+       // Fetch the watch.
+       w.mu.Lock()
+       defer w.mu.Unlock()
+       watch, ok := w.watches[name]
+
+       // Remove it from inotify.
+       if !ok {
+               return fmt.Errorf("can't remove non-existent inotify watch for: 
%s", name)
+       }
+       // inotify_rm_watch will return EINVAL if the file has been deleted;
+       // the inotify will already have been removed.
+       // watches and pathes are deleted in ignoreLinux() implicitly and 
asynchronously
+       // by calling inotify_rm_watch() below. e.g. readEvents() goroutine 
receives IN_IGNORE
+       // so that EINVAL means that the wd is being rm_watch()ed or its file 
removed
+       // by another thread and we have not received IN_IGNORE event.
+       success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
+       if success == -1 {
+               // TODO: Perhaps it's not helpful to return an error here in 
every case.
+               // the only two possible errors are:
+               // EBADF, which happens when w.fd is not a valid file 
descriptor of any kind.
+               // EINVAL, which is when fd is not an inotify descriptor or wd 
is not a valid watch descriptor.
+               // Watch descriptors are invalidated when they are removed 
explicitly or implicitly;
+               // explicitly by inotify_rm_watch, implicitly when the file 
they are watching is deleted.
+               return errno
+       }
+
+       // wait until ignoreLinux() deleting maps
+       exists := true
+       for exists {
+               w.cv.Wait()
+               _, exists = w.watches[name]
+       }
+
+       return nil
+}
+
+type watch struct {
+       wd    uint32 // Watch descriptor (as returned by the 
inotify_add_watch() syscall)
+       flags uint32 // inotify flags of this watch (see inotify(7) for the 
list of valid flags)
+}
+
+// readEvents reads from the inotify file descriptor, converts the
+// received events into Event objects and sends them via the Events channel
+func (w *Watcher) readEvents() {
+       var (
+               buf   [unix.SizeofInotifyEvent * 4096]byte // Buffer for a 
maximum of 4096 raw events
+               n     int                                  // Number of bytes 
read with read()
+               errno error                                // Syscall errno
+               ok    bool                                 // For poller.wait
+       )
+
+       defer close(w.doneResp)
+       defer close(w.Errors)
+       defer close(w.Events)
+       defer unix.Close(w.fd)
+       defer w.poller.close()
+
+       for {
+               // See if we have been closed.
+               if w.isClosed() {
+                       return
+               }
+
+               ok, errno = w.poller.wait()
+               if errno != nil {
+                       select {
+                       case w.Errors <- errno:
+                       case <-w.done:
+                               return
+                       }
+                       continue
+               }
+
+               if !ok {
+                       continue
+               }
+
+               n, errno = unix.Read(w.fd, buf[:])
+               // If a signal interrupted execution, see if we've been asked 
to close, and try again.
+               // http://man7.org/linux/man-pages/man7/signal.7.html :
+               // "Before Linux 3.8, reads from an inotify(7) file descriptor 
were not restartable"
+               if errno == unix.EINTR {
+                       continue
+               }
+
+               // unix.Read might have been woken up by Close. If so, we're 
done.
+               if w.isClosed() {
+                       return
+               }
+
+               if n < unix.SizeofInotifyEvent {
+                       var err error
+                       if n == 0 {
+                               // If EOF is received. This should really never 
happen.
+                               err = io.EOF
+                       } else if n < 0 {
+                               // If an error occurred while reading.
+                               err = errno
+                       } else {
+                               // Read was too short.
+                               err = errors.New("notify: short read in 
readEvents()")
+                       }
+                       select {
+                       case w.Errors <- err:
+                       case <-w.done:
+                               return
+                       }
+                       continue
+               }
+
+               var offset uint32
+               // We don't know how many events we just read into the buffer
+               // While the offset points to at least one whole event...
+               for offset <= uint32(n-unix.SizeofInotifyEvent) {
+                       // Point "raw" to the event in the buffer
+                       raw := 
(*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
+
+                       mask := uint32(raw.Mask)
+                       nameLen := uint32(raw.Len)
+                       // If the event happened to the watched directory or 
the watched file, the kernel
+                       // doesn't append the filename to the event, but we 
would like to always fill the
+                       // the "Name" field with a valid filename. We retrieve 
the path of the watch from
+                       // the "paths" map.
+                       w.mu.Lock()
+                       name := w.paths[int(raw.Wd)]
+                       w.mu.Unlock()
+                       if nameLen > 0 {
+                               // Point "bytes" at the first byte of the 
filename
+                               bytes := 
(*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
+                               // The filename is padded with NULL bytes. 
TrimRight() gets rid of those.
+                               name += "/" + 
strings.TrimRight(string(bytes[0:nameLen]), "\000")
+                       }
+
+                       event := newEvent(name, mask)
+
+                       // Send the events that are not ignored on the events 
channel
+                       if !event.ignoreLinux(w, raw.Wd, mask) {
+                               select {
+                               case w.Events <- event:
+                               case <-w.done:
+                                       return
+                               }
+                       }
+
+                       // Move to the next event in the buffer
+                       offset += unix.SizeofInotifyEvent + nameLen
+               }
+       }
+}
+
+// Certain types of events can be "ignored" and not sent over the Events
+// channel. Such as events marked ignore by the kernel, or MODIFY events
+// against files that do not exist.
+func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool {
+       // Ignore anything the inotify API says to ignore
+       if mask&unix.IN_IGNORED == unix.IN_IGNORED {
+               w.mu.Lock()
+               defer w.mu.Unlock()
+               name := w.paths[int(wd)]
+               delete(w.paths, int(wd))
+               delete(w.watches, name)
+               w.cv.Broadcast()
+               return true
+       }
+
+       // If the event is not a DELETE or RENAME, the file must exist.
+       // Otherwise the event is ignored.
+       // *Note*: this was put in place because it was seen that a MODIFY
+       // event was sent after the DELETE. This ignores that MODIFY and
+       // assumes a DELETE will come or has come if the file doesn't exist.
+       if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
+               _, statErr := os.Lstat(e.Name)
+               return os.IsNotExist(statErr)
+       }
+       return false
+}
+
+// newEvent returns an platform-independent Event based on an inotify mask.
+func newEvent(name string, mask uint32) Event {
+       e := Event{Name: name}
+       if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == 
unix.IN_MOVED_TO {
+               e.Op |= Create
+       }
+       if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || 
mask&unix.IN_DELETE == unix.IN_DELETE {
+               e.Op |= Remove
+       }
+       if mask&unix.IN_MODIFY == unix.IN_MODIFY {
+               e.Op |= Write
+       }
+       if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || 
mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
+               e.Op |= Rename
+       }
+       if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
+               e.Op |= Chmod
+       }
+       return e
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller.go
new file mode 100644
index 0000000..cc7db4b
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+       "errors"
+
+       "golang.org/x/sys/unix"
+)
+
+type fdPoller struct {
+       fd   int    // File descriptor (as returned by the inotify_init() 
syscall)
+       epfd int    // Epoll file descriptor
+       pipe [2]int // Pipe for waking up
+}
+
+func emptyPoller(fd int) *fdPoller {
+       poller := new(fdPoller)
+       poller.fd = fd
+       poller.epfd = -1
+       poller.pipe[0] = -1
+       poller.pipe[1] = -1
+       return poller
+}
+
+// Create a new inotify poller.
+// This creates an inotify handler, and an epoll handler.
+func newFdPoller(fd int) (*fdPoller, error) {
+       var errno error
+       poller := emptyPoller(fd)
+       defer func() {
+               if errno != nil {
+                       poller.close()
+               }
+       }()
+       poller.fd = fd
+
+       // Create epoll fd
+       poller.epfd, errno = unix.EpollCreate1(0)
+       if poller.epfd == -1 {
+               return nil, errno
+       }
+       // Create pipe; pipe[0] is the read end, pipe[1] the write end.
+       errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
+       if errno != nil {
+               return nil, errno
+       }
+
+       // Register inotify fd with epoll
+       event := unix.EpollEvent{
+               Fd:     int32(poller.fd),
+               Events: unix.EPOLLIN,
+       }
+       errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, 
&event)
+       if errno != nil {
+               return nil, errno
+       }
+
+       // Register pipe fd with epoll
+       event = unix.EpollEvent{
+               Fd:     int32(poller.pipe[0]),
+               Events: unix.EPOLLIN,
+       }
+       errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], 
&event)
+       if errno != nil {
+               return nil, errno
+       }
+
+       return poller, nil
+}
+
+// Wait using epoll.
+// Returns true if something is ready to be read,
+// false if there is not.
+func (poller *fdPoller) wait() (bool, error) {
+       // 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
+       // I don't know whether epoll_wait returns the number of events 
returned,
+       // or the total number of events ready.
+       // I decided to catch both by making the buffer one larger than the 
maximum.
+       events := make([]unix.EpollEvent, 7)
+       for {
+               n, errno := unix.EpollWait(poller.epfd, events, -1)
+               if n == -1 {
+                       if errno == unix.EINTR {
+                               continue
+                       }
+                       return false, errno
+               }
+               if n == 0 {
+                       // If there are no events, try again.
+                       continue
+               }
+               if n > 6 {
+                       // This should never happen. More events were returned 
than should be possible.
+                       return false, errors.New("epoll_wait returned more 
events than I know what to do with")
+               }
+               ready := events[:n]
+               epollhup := false
+               epollerr := false
+               epollin := false
+               for _, event := range ready {
+                       if event.Fd == int32(poller.fd) {
+                               if event.Events&unix.EPOLLHUP != 0 {
+                                       // This should not happen, but if it 
does, treat it as a wakeup.
+                                       epollhup = true
+                               }
+                               if event.Events&unix.EPOLLERR != 0 {
+                                       // If an error is waiting on the file 
descriptor, we should pretend
+                                       // something is ready to read, and let 
unix.Read pick up the error.
+                                       epollerr = true
+                               }
+                               if event.Events&unix.EPOLLIN != 0 {
+                                       // There is data to read.
+                                       epollin = true
+                               }
+                       }
+                       if event.Fd == int32(poller.pipe[0]) {
+                               if event.Events&unix.EPOLLHUP != 0 {
+                                       // Write pipe descriptor was closed, by 
us. This means we're closing down the
+                                       // watcher, and we should wake up.
+                               }
+                               if event.Events&unix.EPOLLERR != 0 {
+                                       // If an error is waiting on the pipe 
file descriptor.
+                                       // This is an absolute mystery, and 
should never ever happen.
+                                       return false, errors.New("Error on the 
pipe descriptor.")
+                               }
+                               if event.Events&unix.EPOLLIN != 0 {
+                                       // This is a regular wakeup, so we have 
to clear the buffer.
+                                       err := poller.clearWake()
+                                       if err != nil {
+                                               return false, err
+                                       }
+                               }
+                       }
+               }
+
+               if epollhup || epollerr || epollin {
+                       return true, nil
+               }
+               return false, nil
+       }
+}
+
+// Close the write end of the poller.
+func (poller *fdPoller) wake() error {
+       buf := make([]byte, 1)
+       n, errno := unix.Write(poller.pipe[1], buf)
+       if n == -1 {
+               if errno == unix.EAGAIN {
+                       // Buffer is full, poller will wake.
+                       return nil
+               }
+               return errno
+       }
+       return nil
+}
+
+func (poller *fdPoller) clearWake() error {
+       // You have to be woken up a LOT in order to get to 100!
+       buf := make([]byte, 100)
+       n, errno := unix.Read(poller.pipe[0], buf)
+       if n == -1 {
+               if errno == unix.EAGAIN {
+                       // Buffer is empty, someone else cleared our wake.
+                       return nil
+               }
+               return errno
+       }
+       return nil
+}
+
+// Close all poller file descriptors, but not the one passed to it.
+func (poller *fdPoller) close() {
+       if poller.pipe[1] != -1 {
+               unix.Close(poller.pipe[1])
+       }
+       if poller.pipe[0] != -1 {
+               unix.Close(poller.pipe[0])
+       }
+       if poller.epfd != -1 {
+               unix.Close(poller.epfd)
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go
new file mode 100644
index 0000000..26623ef
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go
@@ -0,0 +1,229 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+       "testing"
+       "time"
+
+       "golang.org/x/sys/unix"
+)
+
+type testFd [2]int
+
+func makeTestFd(t *testing.T) testFd {
+       var tfd testFd
+       errno := unix.Pipe(tfd[:])
+       if errno != nil {
+               t.Fatalf("Failed to create pipe: %v", errno)
+       }
+       return tfd
+}
+
+func (tfd testFd) fd() int {
+       return tfd[0]
+}
+
+func (tfd testFd) closeWrite(t *testing.T) {
+       errno := unix.Close(tfd[1])
+       if errno != nil {
+               t.Fatalf("Failed to close write end of pipe: %v", errno)
+       }
+}
+
+func (tfd testFd) put(t *testing.T) {
+       buf := make([]byte, 10)
+       _, errno := unix.Write(tfd[1], buf)
+       if errno != nil {
+               t.Fatalf("Failed to write to pipe: %v", errno)
+       }
+}
+
+func (tfd testFd) get(t *testing.T) {
+       buf := make([]byte, 10)
+       _, errno := unix.Read(tfd[0], buf)
+       if errno != nil {
+               t.Fatalf("Failed to read from pipe: %v", errno)
+       }
+}
+
+func (tfd testFd) close() {
+       unix.Close(tfd[1])
+       unix.Close(tfd[0])
+}
+
+func makePoller(t *testing.T) (testFd, *fdPoller) {
+       tfd := makeTestFd(t)
+       poller, err := newFdPoller(tfd.fd())
+       if err != nil {
+               t.Fatalf("Failed to create poller: %v", err)
+       }
+       return tfd, poller
+}
+
+func TestPollerWithBadFd(t *testing.T) {
+       _, err := newFdPoller(-1)
+       if err != unix.EBADF {
+               t.Fatalf("Expected EBADF, got: %v", err)
+       }
+}
+
+func TestPollerWithData(t *testing.T) {
+       tfd, poller := makePoller(t)
+       defer tfd.close()
+       defer poller.close()
+
+       tfd.put(t)
+       ok, err := poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if !ok {
+               t.Fatalf("expected poller to return true")
+       }
+       tfd.get(t)
+}
+
+func TestPollerWithWakeup(t *testing.T) {
+       tfd, poller := makePoller(t)
+       defer tfd.close()
+       defer poller.close()
+
+       err := poller.wake()
+       if err != nil {
+               t.Fatalf("wake failed: %v", err)
+       }
+       ok, err := poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if ok {
+               t.Fatalf("expected poller to return false")
+       }
+}
+
+func TestPollerWithClose(t *testing.T) {
+       tfd, poller := makePoller(t)
+       defer tfd.close()
+       defer poller.close()
+
+       tfd.closeWrite(t)
+       ok, err := poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if !ok {
+               t.Fatalf("expected poller to return true")
+       }
+}
+
+func TestPollerWithWakeupAndData(t *testing.T) {
+       tfd, poller := makePoller(t)
+       defer tfd.close()
+       defer poller.close()
+
+       tfd.put(t)
+       err := poller.wake()
+       if err != nil {
+               t.Fatalf("wake failed: %v", err)
+       }
+
+       // both data and wakeup
+       ok, err := poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if !ok {
+               t.Fatalf("expected poller to return true")
+       }
+
+       // data is still in the buffer, wakeup is cleared
+       ok, err = poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if !ok {
+               t.Fatalf("expected poller to return true")
+       }
+
+       tfd.get(t)
+       // data is gone, only wakeup now
+       err = poller.wake()
+       if err != nil {
+               t.Fatalf("wake failed: %v", err)
+       }
+       ok, err = poller.wait()
+       if err != nil {
+               t.Fatalf("poller failed: %v", err)
+       }
+       if ok {
+               t.Fatalf("expected poller to return false")
+       }
+}
+
+func TestPollerConcurrent(t *testing.T) {
+       tfd, poller := makePoller(t)
+       defer tfd.close()
+       defer poller.close()
+
+       oks := make(chan bool)
+       live := make(chan bool)
+       defer close(live)
+       go func() {
+               defer close(oks)
+               for {
+                       ok, err := poller.wait()
+                       if err != nil {
+                               t.Fatalf("poller failed: %v", err)
+                       }
+                       oks <- ok
+                       if !<-live {
+                               return
+                       }
+               }
+       }()
+
+       // Try a write
+       select {
+       case <-time.After(50 * time.Millisecond):
+       case <-oks:
+               t.Fatalf("poller did not wait")
+       }
+       tfd.put(t)
+       if !<-oks {
+               t.Fatalf("expected true")
+       }
+       tfd.get(t)
+       live <- true
+
+       // Try a wakeup
+       select {
+       case <-time.After(50 * time.Millisecond):
+       case <-oks:
+               t.Fatalf("poller did not wait")
+       }
+       err := poller.wake()
+       if err != nil {
+               t.Fatalf("wake failed: %v", err)
+       }
+       if <-oks {
+               t.Fatalf("expected false")
+       }
+       live <- true
+
+       // Try a close
+       select {
+       case <-time.After(50 * time.Millisecond):
+       case <-oks:
+               t.Fatalf("poller did not wait")
+       }
+       tfd.closeWrite(t)
+       if !<-oks {
+               t.Fatalf("expected true")
+       }
+       tfd.get(t)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_test.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_test.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_test.go
new file mode 100644
index 0000000..2527cad
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/inotify_test.go
@@ -0,0 +1,344 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+       "fmt"
+       "os"
+       "path/filepath"
+       "testing"
+       "time"
+
+       "golang.org/x/sys/unix"
+)
+
+func TestInotifyCloseRightAway(t *testing.T) {
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher")
+       }
+
+       // Close immediately; it won't even reach the first unix.Read.
+       w.Close()
+
+       // Wait for the close to complete.
+       <-time.After(50 * time.Millisecond)
+       isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseSlightlyLater(t *testing.T) {
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher")
+       }
+
+       // Wait until readEvents has reached unix.Read, and Close.
+       <-time.After(50 * time.Millisecond)
+       w.Close()
+
+       // Wait for the close to complete.
+       <-time.After(50 * time.Millisecond)
+       isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher")
+       }
+       w.Add(testDir)
+
+       // Wait until readEvents has reached unix.Read, and Close.
+       <-time.After(50 * time.Millisecond)
+       w.Close()
+
+       // Wait for the close to complete.
+       <-time.After(50 * time.Millisecond)
+       isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseAfterRead(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher")
+       }
+
+       err = w.Add(testDir)
+       if err != nil {
+               t.Fatalf("Failed to add .")
+       }
+
+       // Generate an event.
+       os.Create(filepath.Join(testDir, 
"somethingSOMETHINGsomethingSOMETHING"))
+
+       // Wait for readEvents to read the event, then close the watcher.
+       <-time.After(50 * time.Millisecond)
+       w.Close()
+
+       // Wait for the close to complete.
+       <-time.After(50 * time.Millisecond)
+       isWatcherReallyClosed(t, w)
+}
+
+func isWatcherReallyClosed(t *testing.T, w *Watcher) {
+       select {
+       case err, ok := <-w.Errors:
+               if ok {
+                       t.Fatalf("w.Errors is not closed; readEvents is still 
alive after closing (error: %v)", err)
+               }
+       default:
+               t.Fatalf("w.Errors would have blocked; readEvents is still 
alive!")
+       }
+
+       select {
+       case _, ok := <-w.Events:
+               if ok {
+                       t.Fatalf("w.Events is not closed; readEvents is still 
alive after closing")
+               }
+       default:
+               t.Fatalf("w.Events would have blocked; readEvents is still 
alive!")
+       }
+}
+
+func TestInotifyCloseCreate(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher: %v", err)
+       }
+       defer w.Close()
+
+       err = w.Add(testDir)
+       if err != nil {
+               t.Fatalf("Failed to add testDir: %v", err)
+       }
+       h, err := os.Create(filepath.Join(testDir, "testfile"))
+       if err != nil {
+               t.Fatalf("Failed to create file in testdir: %v", err)
+       }
+       h.Close()
+       select {
+       case _ = <-w.Events:
+       case err := <-w.Errors:
+               t.Fatalf("Error from watcher: %v", err)
+       case <-time.After(50 * time.Millisecond):
+               t.Fatalf("Took too long to wait for event")
+       }
+
+       // At this point, we've received one event, so the goroutine is ready.
+       // It's also blocking on unix.Read.
+       // Now we try to swap the file descriptor under its nose.
+       w.Close()
+       w, err = NewWatcher()
+       defer w.Close()
+       if err != nil {
+               t.Fatalf("Failed to create second watcher: %v", err)
+       }
+
+       <-time.After(50 * time.Millisecond)
+       err = w.Add(testDir)
+       if err != nil {
+               t.Fatalf("Error adding testDir again: %v", err)
+       }
+}
+
+func TestInotifyStress(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+       testFile := filepath.Join(testDir, "testfile")
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher: %v", err)
+       }
+       defer w.Close()
+
+       killchan := make(chan struct{})
+       defer close(killchan)
+
+       err = w.Add(testDir)
+       if err != nil {
+               t.Fatalf("Failed to add testDir: %v", err)
+       }
+
+       proc, err := os.FindProcess(os.Getpid())
+       if err != nil {
+               t.Fatalf("Error finding process: %v", err)
+       }
+
+       go func() {
+               for {
+                       select {
+                       case <-time.After(5 * time.Millisecond):
+                               err := proc.Signal(unix.SIGUSR1)
+                               if err != nil {
+                                       t.Fatalf("Signal failed: %v", err)
+                               }
+                       case <-killchan:
+                               return
+                       }
+               }
+       }()
+
+       go func() {
+               for {
+                       select {
+                       case <-time.After(11 * time.Millisecond):
+                               err := w.poller.wake()
+                               if err != nil {
+                                       t.Fatalf("Wake failed: %v", err)
+                               }
+                       case <-killchan:
+                               return
+                       }
+               }
+       }()
+
+       go func() {
+               for {
+                       select {
+                       case <-killchan:
+                               return
+                       default:
+                               handle, err := os.Create(testFile)
+                               if err != nil {
+                                       t.Fatalf("Create failed: %v", err)
+                               }
+                               handle.Close()
+                               time.Sleep(time.Millisecond)
+                               err = os.Remove(testFile)
+                               if err != nil {
+                                       t.Fatalf("Remove failed: %v", err)
+                               }
+                       }
+               }
+       }()
+
+       creates := 0
+       removes := 0
+       after := time.After(5 * time.Second)
+       for {
+               select {
+               case <-after:
+                       if creates-removes > 1 || creates-removes < -1 {
+                               t.Fatalf("Creates and removes should not be off 
by more than one: %d creates, %d removes", creates, removes)
+                       }
+                       if creates < 50 {
+                               t.Fatalf("Expected at least 50 creates, got 
%d", creates)
+                       }
+                       return
+               case err := <-w.Errors:
+                       t.Fatalf("Got an error from watcher: %v", err)
+               case evt := <-w.Events:
+                       if evt.Name != testFile {
+                               t.Fatalf("Got an event for an unknown file: 
%s", evt.Name)
+                       }
+                       if evt.Op == Create {
+                               creates++
+                       }
+                       if evt.Op == Remove {
+                               removes++
+                       }
+               }
+       }
+}
+
+func TestInotifyRemoveTwice(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+       testFile := filepath.Join(testDir, "testfile")
+
+       handle, err := os.Create(testFile)
+       if err != nil {
+               t.Fatalf("Create failed: %v", err)
+       }
+       handle.Close()
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher: %v", err)
+       }
+       defer w.Close()
+
+       err = w.Add(testFile)
+       if err != nil {
+               t.Fatalf("Failed to add testFile: %v", err)
+       }
+
+       err = os.Remove(testFile)
+       if err != nil {
+               t.Fatalf("Failed to remove testFile: %v", err)
+       }
+
+       err = w.Remove(testFile)
+       if err == nil {
+               t.Fatalf("no error on removing invalid file")
+       }
+       s1 := fmt.Sprintf("%s", err)
+
+       err = w.Remove(testFile)
+       if err == nil {
+               t.Fatalf("no error on removing invalid file")
+       }
+       s2 := fmt.Sprintf("%s", err)
+
+       if s1 != s2 {
+               t.Fatalf("receive different error - %s / %s", s1, s2)
+       }
+}
+
+func TestInotifyInnerMapLength(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+       testFile := filepath.Join(testDir, "testfile")
+
+       handle, err := os.Create(testFile)
+       if err != nil {
+               t.Fatalf("Create failed: %v", err)
+       }
+       handle.Close()
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher: %v", err)
+       }
+       defer w.Close()
+
+       err = w.Add(testFile)
+       if err != nil {
+               t.Fatalf("Failed to add testFile: %v", err)
+       }
+       go func() {
+               for err := range w.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       err = os.Remove(testFile)
+       if err != nil {
+               t.Fatalf("Failed to remove testFile: %v", err)
+       }
+       _ = <-w.Events                      // consume Remove event
+       <-time.After(50 * time.Millisecond) // wait IN_IGNORE propagated
+
+       w.mu.Lock()
+       defer w.mu.Unlock()
+       if len(w.watches) != 0 {
+               t.Fatalf("Expected watches len is 0, but got: %d, %v", 
len(w.watches), w.watches)
+       }
+       if len(w.paths) != 0 {
+               t.Fatalf("Expected paths len is 0, but got: %d, %v", 
len(w.paths), w.paths)
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go
new file mode 100644
index 0000000..5564554
--- /dev/null
+++ 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go
@@ -0,0 +1,147 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fsnotify
+
+import (
+       "os"
+       "path/filepath"
+       "testing"
+       "time"
+
+       "golang.org/x/sys/unix"
+)
+
+// testExchangedataForWatcher tests the watcher with the exchangedata 
operation on OS X.
+//
+// This is widely used for atomic saves on OS X, e.g. TextMate and in Apple's 
NSDocument.
+//
+// See 
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
+// Also see: 
https://github.com/textmate/textmate/blob/cd016be29489eba5f3c09b7b70b06da134dda550/Frameworks/io/src/swap_file_data.cc#L20
+func testExchangedataForWatcher(t *testing.T, watchDir bool) {
+       // Create directory to watch
+       testDir1 := tempMkdir(t)
+
+       // For the intermediate file
+       testDir2 := tempMkdir(t)
+
+       defer os.RemoveAll(testDir1)
+       defer os.RemoveAll(testDir2)
+
+       resolvedFilename := "TestFsnotifyEvents.file"
+
+       // TextMate does:
+       //
+       // 1. exchangedata (intermediate, resolved)
+       // 2. unlink intermediate
+       //
+       // Let's try to simulate that:
+       resolved := filepath.Join(testDir1, resolvedFilename)
+       intermediate := filepath.Join(testDir2, resolvedFilename+"~")
+
+       // Make sure we create the file before we start watching
+       createAndSyncFile(t, resolved)
+
+       watcher := newWatcher(t)
+
+       // Test both variants in isolation
+       if watchDir {
+               addWatch(t, watcher, testDir1)
+       } else {
+               addWatch(t, watcher, resolved)
+       }
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var removeReceived counter
+       var createReceived counter
+
+       done := make(chan bool)
+
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(resolved) {
+                               if event.Op&Remove == Remove {
+                                       removeReceived.increment()
+                               }
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                       }
+                       t.Logf("event received: %s", event)
+               }
+               done <- true
+       }()
+
+       // Repeat to make sure the watched file/directory "survives" the 
REMOVE/CREATE loop.
+       for i := 1; i <= 3; i++ {
+               // The intermediate file is created in a folder outside the 
watcher
+               createAndSyncFile(t, intermediate)
+
+               // 1. Swap
+               if err := unix.Exchangedata(intermediate, resolved, 0); err != 
nil {
+                       t.Fatalf("[%d] exchangedata failed: %s", i, err)
+               }
+
+               time.Sleep(50 * time.Millisecond)
+
+               // 2. Delete the intermediate file
+               err := os.Remove(intermediate)
+
+               if err != nil {
+                       t.Fatalf("[%d] remove %s failed: %s", i, intermediate, 
err)
+               }
+
+               time.Sleep(50 * time.Millisecond)
+
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+
+       // The events will be (CHMOD + REMOVE + CREATE) X 2. Let's focus on the 
last two:
+       if removeReceived.value() < 3 {
+               t.Fatal("fsnotify remove events have not been received after 
500 ms")
+       }
+
+       if createReceived.value() < 3 {
+               t.Fatal("fsnotify create events have not been received after 
500 ms")
+       }
+
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+}
+
+// TestExchangedataInWatchedDir test exchangedata operation on file in watched 
dir.
+func TestExchangedataInWatchedDir(t *testing.T) {
+       testExchangedataForWatcher(t, true)
+}
+
+// TestExchangedataInWatchedDir test exchangedata operation on watched file.
+func TestExchangedataInWatchedFile(t *testing.T) {
+       testExchangedataForWatcher(t, false)
+}
+
+func createAndSyncFile(t *testing.T, filepath string) {
+       f1, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating %s failed: %s", filepath, err)
+       }
+       f1.Sync()
+       f1.Close()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_test.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_test.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_test.go
new file mode 100644
index 0000000..8b7e9d3
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/integration_test.go
@@ -0,0 +1,1237 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!solaris
+
+package fsnotify
+
+import (
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path"
+       "path/filepath"
+       "runtime"
+       "sync/atomic"
+       "testing"
+       "time"
+)
+
+// An atomic counter
+type counter struct {
+       val int32
+}
+
+func (c *counter) increment() {
+       atomic.AddInt32(&c.val, 1)
+}
+
+func (c *counter) value() int32 {
+       return atomic.LoadInt32(&c.val)
+}
+
+func (c *counter) reset() {
+       atomic.StoreInt32(&c.val, 0)
+}
+
+// tempMkdir makes a temporary directory
+func tempMkdir(t *testing.T) string {
+       dir, err := ioutil.TempDir("", "fsnotify")
+       if err != nil {
+               t.Fatalf("failed to create test directory: %s", err)
+       }
+       return dir
+}
+
+// tempMkFile makes a temporary file.
+func tempMkFile(t *testing.T, dir string) string {
+       f, err := ioutil.TempFile(dir, "fsnotify")
+       if err != nil {
+               t.Fatalf("failed to create test file: %v", err)
+       }
+       defer f.Close()
+       return f.Name()
+}
+
+// newWatcher initializes an fsnotify Watcher instance.
+func newWatcher(t *testing.T) *Watcher {
+       watcher, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("NewWatcher() failed: %s", err)
+       }
+       return watcher
+}
+
+// addWatch adds a watch for a directory
+func addWatch(t *testing.T, watcher *Watcher, dir string) {
+       if err := watcher.Add(dir); err != nil {
+               t.Fatalf("watcher.Add(%q) failed: %s", dir, err)
+       }
+}
+
+func TestFsnotifyMultipleOperations(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create directory that's not watched
+       testDirToMoveFiles := tempMkdir(t)
+       defer os.RemoveAll(testDirToMoveFiles)
+
+       testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
+       testFileRenamed := filepath.Join(testDirToMoveFiles, 
"TestFsnotifySeqRename.testfile")
+
+       addWatch(t, watcher, testDir)
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var createReceived, modifyReceived, deleteReceived, renameReceived 
counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) {
+                               t.Logf("event received: %s", event)
+                               if event.Op&Remove == Remove {
+                                       deleteReceived.increment()
+                               }
+                               if event.Op&Write == Write {
+                                       modifyReceived.increment()
+                               }
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                               if event.Op&Rename == Rename {
+                                       renameReceived.increment()
+                               }
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       time.Sleep(time.Millisecond)
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       if err := testRename(testFile, testFileRenamed); err != nil {
+               t.Fatalf("rename failed: %s", err)
+       }
+
+       // Modify the file outside of the watched dir
+       f, err = os.Open(testFileRenamed)
+       if err != nil {
+               t.Fatalf("open test renamed file failed: %s", err)
+       }
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // Recreate the file that was moved
+       f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Close()
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       cReceived := createReceived.value()
+       if cReceived != 2 {
+               t.Fatalf("incorrect number of create events received after 500 
ms (%d vs %d)", cReceived, 2)
+       }
+       mReceived := modifyReceived.value()
+       if mReceived != 1 {
+               t.Fatalf("incorrect number of modify events received after 500 
ms (%d vs %d)", mReceived, 1)
+       }
+       dReceived := deleteReceived.value()
+       rReceived := renameReceived.value()
+       if dReceived+rReceived != 1 {
+               t.Fatalf("incorrect number of rename+delete events received 
after 500 ms (%d vs %d)", rReceived+dReceived, 1)
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+}
+
+func TestFsnotifyMultipleCreates(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
+
+       addWatch(t, watcher, testDir)
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var createReceived, modifyReceived, deleteReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) {
+                               t.Logf("event received: %s", event)
+                               if event.Op&Remove == Remove {
+                                       deleteReceived.increment()
+                               }
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                               if event.Op&Write == Write {
+                                       modifyReceived.increment()
+                               }
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       time.Sleep(time.Millisecond)
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       os.Remove(testFile)
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // Recreate the file
+       f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Close()
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // Modify
+       f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       time.Sleep(time.Millisecond)
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // Modify
+       f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       time.Sleep(time.Millisecond)
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       cReceived := createReceived.value()
+       if cReceived != 2 {
+               t.Fatalf("incorrect number of create events received after 500 
ms (%d vs %d)", cReceived, 2)
+       }
+       mReceived := modifyReceived.value()
+       if mReceived < 3 {
+               t.Fatalf("incorrect number of modify events received after 500 
ms (%d vs atleast %d)", mReceived, 3)
+       }
+       dReceived := deleteReceived.value()
+       if dReceived != 1 {
+               t.Fatalf("incorrect number of rename+delete events received 
after 500 ms (%d vs %d)", dReceived, 1)
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+}
+
+func TestFsnotifyDirOnly(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create a file before watching directory
+       // This should NOT add any events to the fsnotify event queue
+       testFileAlreadyExists := filepath.Join(testDir, 
"TestFsnotifyEventsExisting.testfile")
+       {
+               var f *os.File
+               f, err := os.OpenFile(testFileAlreadyExists, 
os.O_WRONLY|os.O_CREATE, 0666)
+               if err != nil {
+                       t.Fatalf("creating test file failed: %s", err)
+               }
+               f.Sync()
+               f.Close()
+       }
+
+       addWatch(t, watcher, testDir)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var createReceived, modifyReceived, deleteReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) || event.Name == 
filepath.Clean(testFileAlreadyExists) {
+                               t.Logf("event received: %s", event)
+                               if event.Op&Remove == Remove {
+                                       deleteReceived.increment()
+                               }
+                               if event.Op&Write == Write {
+                                       modifyReceived.increment()
+                               }
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       time.Sleep(time.Millisecond)
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(50 * time.Millisecond) // give system time to sync write 
change before delete
+
+       os.Remove(testFile)
+       os.Remove(testFileAlreadyExists)
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       cReceived := createReceived.value()
+       if cReceived != 1 {
+               t.Fatalf("incorrect number of create events received after 500 
ms (%d vs %d)", cReceived, 1)
+       }
+       mReceived := modifyReceived.value()
+       if mReceived != 1 {
+               t.Fatalf("incorrect number of modify events received after 500 
ms (%d vs %d)", mReceived, 1)
+       }
+       dReceived := deleteReceived.value()
+       if dReceived != 2 {
+               t.Fatalf("incorrect number of delete events received after 500 
ms (%d vs %d)", dReceived, 2)
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+}
+
+func TestFsnotifyDeleteWatchedDir(t *testing.T) {
+       watcher := newWatcher(t)
+       defer watcher.Close()
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create a file before watching directory
+       testFileAlreadyExists := filepath.Join(testDir, 
"TestFsnotifyEventsExisting.testfile")
+       {
+               var f *os.File
+               f, err := os.OpenFile(testFileAlreadyExists, 
os.O_WRONLY|os.O_CREATE, 0666)
+               if err != nil {
+                       t.Fatalf("creating test file failed: %s", err)
+               }
+               f.Sync()
+               f.Close()
+       }
+
+       addWatch(t, watcher, testDir)
+
+       // Add a watch for testFile
+       addWatch(t, watcher, testFileAlreadyExists)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var deleteReceived counter
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFileAlreadyExists) {
+                               t.Logf("event received: %s", event)
+                               if event.Op&Remove == Remove {
+                                       deleteReceived.increment()
+                               }
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+       }()
+
+       os.RemoveAll(testDir)
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       dReceived := deleteReceived.value()
+       if dReceived < 2 {
+               t.Fatalf("did not receive at least %d delete events, received 
%d after 500 ms", 2, dReceived)
+       }
+}
+
+func TestFsnotifySubDir(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
+       testSubDir := filepath.Join(testDir, "sub")
+       testSubDirFile := filepath.Join(testDir, 
"sub/TestFsnotifyFile1.testfile")
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var createReceived, deleteReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
+                               t.Logf("event received: %s", event)
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                               if event.Op&Remove == Remove {
+                                       deleteReceived.increment()
+                               }
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       addWatch(t, watcher, testDir)
+
+       // Create sub-directory
+       if err := os.Mkdir(testSubDir, 0777); err != nil {
+               t.Fatalf("failed to create test sub-directory: %s", err)
+       }
+
+       // Create a file
+       var f *os.File
+       f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+       f.Close()
+
+       // Create a file (Should not see this! we are not watching subdir)
+       var fs *os.File
+       fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       fs.Sync()
+       fs.Close()
+
+       time.Sleep(200 * time.Millisecond)
+
+       // Make sure receive deletes for both file and sub-directory
+       os.RemoveAll(testSubDir)
+       os.Remove(testFile1)
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       cReceived := createReceived.value()
+       if cReceived != 2 {
+               t.Fatalf("incorrect number of create events received after 500 
ms (%d vs %d)", cReceived, 2)
+       }
+       dReceived := deleteReceived.value()
+       if dReceived != 2 {
+               t.Fatalf("incorrect number of delete events received after 500 
ms (%d vs %d)", dReceived, 2)
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+}
+
+func TestFsnotifyRename(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       addWatch(t, watcher, testDir)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
+       testFileRenamed := filepath.Join(testDir, 
"TestFsnotifyEvents.testfileRenamed")
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var renameReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
+                               if event.Op&Rename == Rename {
+                                       renameReceived.increment()
+                               }
+                               t.Logf("event received: %s", event)
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       // Add a watch for testFile
+       addWatch(t, watcher, testFile)
+
+       if err := testRename(testFile, testFileRenamed); err != nil {
+               t.Fatalf("rename failed: %s", err)
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       if renameReceived.value() == 0 {
+               t.Fatal("fsnotify rename events have not been received after 
500 ms")
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+
+       os.Remove(testFileRenamed)
+}
+
+func TestFsnotifyRenameToCreate(t *testing.T) {
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create directory to get file
+       testDirFrom := tempMkdir(t)
+       defer os.RemoveAll(testDirFrom)
+
+       addWatch(t, watcher, testDir)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
+       testFileRenamed := filepath.Join(testDir, 
"TestFsnotifyEvents.testfileRenamed")
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var createReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
+                               if event.Op&Create == Create {
+                                       createReceived.increment()
+                               }
+                               t.Logf("event received: %s", event)
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+       f.Close()
+
+       if err := testRename(testFile, testFileRenamed); err != nil {
+               t.Fatalf("rename failed: %s", err)
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       if createReceived.value() == 0 {
+               t.Fatal("fsnotify create events have not been received after 
500 ms")
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+
+       os.Remove(testFileRenamed)
+}
+
+func TestFsnotifyRenameToOverwrite(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               t.Skipf("skipping test on %q (os.Rename over existing file does 
not create event).", runtime.GOOS)
+       }
+
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create directory to get file
+       testDirFrom := tempMkdir(t)
+       defer os.RemoveAll(testDirFrom)
+
+       testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
+       testFileRenamed := filepath.Join(testDir, 
"TestFsnotifyEvents.testfileRenamed")
+
+       // Create a file
+       var fr *os.File
+       fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       fr.Sync()
+       fr.Close()
+
+       addWatch(t, watcher, testDir)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       var eventReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testFileRenamed) {
+                               eventReceived.increment()
+                               t.Logf("event received: %s", event)
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+       f.Close()
+
+       if err := testRename(testFile, testFileRenamed); err != nil {
+               t.Fatalf("rename failed: %s", err)
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+       if eventReceived.value() == 0 {
+               t.Fatal("fsnotify events have not been received after 500 ms")
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(2 * time.Second):
+               t.Fatal("event stream was not closed after 2 seconds")
+       }
+
+       os.Remove(testFileRenamed)
+}
+
+func TestRemovalOfWatch(t *testing.T) {
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create a file before watching directory
+       testFileAlreadyExists := filepath.Join(testDir, 
"TestFsnotifyEventsExisting.testfile")
+       {
+               var f *os.File
+               f, err := os.OpenFile(testFileAlreadyExists, 
os.O_WRONLY|os.O_CREATE, 0666)
+               if err != nil {
+                       t.Fatalf("creating test file failed: %s", err)
+               }
+               f.Sync()
+               f.Close()
+       }
+
+       watcher := newWatcher(t)
+       defer watcher.Close()
+
+       addWatch(t, watcher, testDir)
+       if err := watcher.Remove(testDir); err != nil {
+               t.Fatalf("Could not remove the watch: %v\n", err)
+       }
+
+       go func() {
+               select {
+               case ev := <-watcher.Events:
+                       t.Fatalf("We received event: %v\n", ev)
+               case <-time.After(500 * time.Millisecond):
+                       t.Log("No event received, as expected.")
+               }
+       }()
+
+       time.Sleep(200 * time.Millisecond)
+       // Modify the file outside of the watched dir
+       f, err := os.Open(testFileAlreadyExists)
+       if err != nil {
+               t.Fatalf("Open test file failed: %s", err)
+       }
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+       if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
+               t.Fatalf("chmod failed: %s", err)
+       }
+       time.Sleep(400 * time.Millisecond)
+}
+
+func TestFsnotifyAttrib(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("attributes don't work on Windows.")
+       }
+
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for err := range watcher.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
+
+       // Receive events on the event channel on a separate goroutine
+       eventstream := watcher.Events
+       // The modifyReceived counter counts IsModify events that are not 
IsAttrib,
+       // and the attribReceived counts IsAttrib events (which are also 
IsModify as
+       // a consequence).
+       var modifyReceived counter
+       var attribReceived counter
+       done := make(chan bool)
+       go func() {
+               for event := range eventstream {
+                       // Only count relevant events
+                       if event.Name == filepath.Clean(testDir) || event.Name 
== filepath.Clean(testFile) {
+                               if event.Op&Write == Write {
+                                       modifyReceived.increment()
+                               }
+                               if event.Op&Chmod == Chmod {
+                                       attribReceived.increment()
+                               }
+                               t.Logf("event received: %s", event)
+                       } else {
+                               t.Logf("unexpected event received: %s", event)
+                       }
+               }
+               done <- true
+       }()
+
+       // Create a file
+       // This should add at least one event to the fsnotify event queue
+       var f *os.File
+       f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+
+       f.WriteString("data")
+       f.Sync()
+       f.Close()
+
+       // Add a watch for testFile
+       addWatch(t, watcher, testFile)
+
+       if err := os.Chmod(testFile, 0700); err != nil {
+               t.Fatalf("chmod failed: %s", err)
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       // Creating/writing a file changes also the mtime, so IsAttrib should 
be set to true here
+       time.Sleep(500 * time.Millisecond)
+       if modifyReceived.value() != 0 {
+               t.Fatal("received an unexpected modify event when creating a 
test file")
+       }
+       if attribReceived.value() == 0 {
+               t.Fatal("fsnotify attribute events have not received after 500 
ms")
+       }
+
+       // Modifying the contents of the file does not set the attrib flag 
(although eg. the mtime
+       // might have been modified).
+       modifyReceived.reset()
+       attribReceived.reset()
+
+       f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
+       if err != nil {
+               t.Fatalf("reopening test file failed: %s", err)
+       }
+
+       f.WriteString("more data")
+       f.Sync()
+       f.Close()
+
+       time.Sleep(500 * time.Millisecond)
+
+       if modifyReceived.value() != 1 {
+               t.Fatal("didn't receive a modify event after changing test file 
contents")
+       }
+
+       if attribReceived.value() != 0 {
+               t.Fatal("did receive an unexpected attrib event after changing 
test file contents")
+       }
+
+       modifyReceived.reset()
+       attribReceived.reset()
+
+       // Doing a chmod on the file should trigger an event with the "attrib" 
flag set (the contents
+       // of the file are not changed though)
+       if err := os.Chmod(testFile, 0600); err != nil {
+               t.Fatalf("chmod failed: %s", err)
+       }
+
+       time.Sleep(500 * time.Millisecond)
+
+       if attribReceived.value() != 1 {
+               t.Fatal("didn't receive an attribute change after 500ms")
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+       t.Log("waiting for the event channel to become closed...")
+       select {
+       case <-done:
+               t.Log("event channel closed")
+       case <-time.After(1e9):
+               t.Fatal("event stream was not closed after 1 second")
+       }
+
+       os.Remove(testFile)
+}
+
+func TestFsnotifyClose(t *testing.T) {
+       watcher := newWatcher(t)
+       watcher.Close()
+
+       var done int32
+       go func() {
+               watcher.Close()
+               atomic.StoreInt32(&done, 1)
+       }()
+
+       time.Sleep(50e6) // 50 ms
+       if atomic.LoadInt32(&done) == 0 {
+               t.Fatal("double Close() test failed: second Close() call didn't 
return")
+       }
+
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       if err := watcher.Add(testDir); err == nil {
+               t.Fatal("expected error on Watch() after Close(), got nil")
+       }
+}
+
+func TestFsnotifyFakeSymlink(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("symlinks don't work on Windows.")
+       }
+
+       watcher := newWatcher(t)
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       var errorsReceived counter
+       // Receive errors on the error channel on a separate goroutine
+       go func() {
+               for errors := range watcher.Errors {
+                       t.Logf("Received error: %s", errors)
+                       errorsReceived.increment()
+               }
+       }()
+
+       // Count the CREATE events received
+       var createEventsReceived, otherEventsReceived counter
+       go func() {
+               for ev := range watcher.Events {
+                       t.Logf("event received: %s", ev)
+                       if ev.Op&Create == Create {
+                               createEventsReceived.increment()
+                       } else {
+                               otherEventsReceived.increment()
+                       }
+               }
+       }()
+
+       addWatch(t, watcher, testDir)
+
+       if err := os.Symlink(filepath.Join(testDir, "zzz"), 
filepath.Join(testDir, "zzznew")); err != nil {
+               t.Fatalf("Failed to create bogus symlink: %s", err)
+       }
+       t.Logf("Created bogus symlink")
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+
+       // Should not be error, just no events for broken links (watching 
nothing)
+       if errorsReceived.value() > 0 {
+               t.Fatal("fsnotify errors have been received.")
+       }
+       if otherEventsReceived.value() > 0 {
+               t.Fatal("fsnotify other events received on the broken link")
+       }
+
+       // Except for 1 create event (for the link itself)
+       if createEventsReceived.value() == 0 {
+               t.Fatal("fsnotify create events were not received after 500 ms")
+       }
+       if createEventsReceived.value() > 1 {
+               t.Fatal("fsnotify more create events received than expected")
+       }
+
+       // Try closing the fsnotify instance
+       t.Log("calling Close()")
+       watcher.Close()
+}
+
+func TestCyclicSymlink(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skip("symlinks don't work on Windows.")
+       }
+
+       watcher := newWatcher(t)
+
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       link := path.Join(testDir, "link")
+       if err := os.Symlink(".", link); err != nil {
+               t.Fatalf("could not make symlink: %v", err)
+       }
+       addWatch(t, watcher, testDir)
+
+       var createEventsReceived counter
+       go func() {
+               for ev := range watcher.Events {
+                       if ev.Op&Create == Create {
+                               createEventsReceived.increment()
+                       }
+               }
+       }()
+
+       if err := os.Remove(link); err != nil {
+               t.Fatalf("Error removing link: %v", err)
+       }
+
+       // It would be nice to be able to expect a delete event here, but 
kqueue has
+       // no way for us to get events on symlinks themselves, because opening 
them
+       // opens an fd to the file to which they point.
+
+       if err := ioutil.WriteFile(link, []byte("foo"), 0700); err != nil {
+               t.Fatalf("could not make symlink: %v", err)
+       }
+
+       // We expect this event to be received almost immediately, but let's 
wait 500 ms to be sure
+       time.Sleep(500 * time.Millisecond)
+
+       if got := createEventsReceived.value(); got == 0 {
+               t.Errorf("want at least 1 create event got %v", got)
+       }
+
+       watcher.Close()
+}
+
+// TestConcurrentRemovalOfWatch tests that concurrent calls to RemoveWatch do 
not race.
+// See https://codereview.appspot.com/103300045/
+// go test -test.run=TestConcurrentRemovalOfWatch -test.cpu=1,1,1,1,1 -race
+func TestConcurrentRemovalOfWatch(t *testing.T) {
+       if runtime.GOOS != "darwin" {
+               t.Skip("regression test for race only present on darwin")
+       }
+
+       // Create directory to watch
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       // Create a file before watching directory
+       testFileAlreadyExists := filepath.Join(testDir, 
"TestFsnotifyEventsExisting.testfile")
+       {
+               var f *os.File
+               f, err := os.OpenFile(testFileAlreadyExists, 
os.O_WRONLY|os.O_CREATE, 0666)
+               if err != nil {
+                       t.Fatalf("creating test file failed: %s", err)
+               }
+               f.Sync()
+               f.Close()
+       }
+
+       watcher := newWatcher(t)
+       defer watcher.Close()
+
+       addWatch(t, watcher, testDir)
+
+       // Test that RemoveWatch can be invoked concurrently, with no data 
races.
+       removed1 := make(chan struct{})
+       go func() {
+               defer close(removed1)
+               watcher.Remove(testDir)
+       }()
+       removed2 := make(chan struct{})
+       go func() {
+               close(removed2)
+               watcher.Remove(testDir)
+       }()
+       <-removed1
+       <-removed2
+}
+
+func TestClose(t *testing.T) {
+       // Regression test for #59 bad file descriptor from Close
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       watcher := newWatcher(t)
+       if err := watcher.Add(testDir); err != nil {
+               t.Fatalf("Expected no error on Add, got %v", err)
+       }
+       err := watcher.Close()
+       if err != nil {
+               t.Fatalf("Expected no error on Close, got %v.", err)
+       }
+}
+
+// TestRemoveWithClose tests if one can handle Remove events and, at the same
+// time, close Watcher object without any data races.
+func TestRemoveWithClose(t *testing.T) {
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       const fileN = 200
+       tempFiles := make([]string, 0, fileN)
+       for i := 0; i < fileN; i++ {
+               tempFiles = append(tempFiles, tempMkFile(t, testDir))
+       }
+       watcher := newWatcher(t)
+       if err := watcher.Add(testDir); err != nil {
+               t.Fatalf("Expected no error on Add, got %v", err)
+       }
+       startC, stopC := make(chan struct{}), make(chan struct{})
+       errC := make(chan error)
+       go func() {
+               for {
+                       select {
+                       case <-watcher.Errors:
+                       case <-watcher.Events:
+                       case <-stopC:
+                               return
+                       }
+               }
+       }()
+       go func() {
+               <-startC
+               for _, fileName := range tempFiles {
+                       os.Remove(fileName)
+               }
+       }()
+       go func() {
+               <-startC
+               errC <- watcher.Close()
+       }()
+       close(startC)
+       defer close(stopC)
+       if err := <-errC; err != nil {
+               t.Fatalf("Expected no error on Close, got %v.", err)
+       }
+}
+
+func testRename(file1, file2 string) error {
+       switch runtime.GOOS {
+       case "windows", "plan9":
+               return os.Rename(file1, file2)
+       default:
+               cmd := exec.Command("mv", file1, file2)
+               return cmd.Run()
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/kqueue.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/kqueue.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/kqueue.go
new file mode 100644
index 0000000..c2b4acb
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/kqueue.go
@@ -0,0 +1,503 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd openbsd netbsd dragonfly darwin
+
+package fsnotify
+
+import (
+       "errors"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "sync"
+       "time"
+
+       "golang.org/x/sys/unix"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+       Events chan Event
+       Errors chan error
+       done   chan bool // Channel for sending a "quit message" to the reader 
goroutine
+
+       kq int // File descriptor (as returned by the kqueue() syscall).
+
+       mu              sync.Mutex        // Protects access to watcher data
+       watches         map[string]int    // Map of watched file descriptors 
(key: path).
+       externalWatches map[string]bool   // Map of watches added by user of 
the library.
+       dirFlags        map[string]uint32 // Map of watched directories to 
fflags used in kqueue.
+       paths           map[int]pathInfo  // Map file descriptors to path names 
for processing kqueue events.
+       fileExists      map[string]bool   // Keep track of if we know this file 
exists (to stop duplicate create events).
+       isClosed        bool              // Set to true when Close() is first 
called
+}
+
+type pathInfo struct {
+       name  string
+       isDir bool
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins 
waiting for events.
+func NewWatcher() (*Watcher, error) {
+       kq, err := kqueue()
+       if err != nil {
+               return nil, err
+       }
+
+       w := &Watcher{
+               kq:              kq,
+               watches:         make(map[string]int),
+               dirFlags:        make(map[string]uint32),
+               paths:           make(map[int]pathInfo),
+               fileExists:      make(map[string]bool),
+               externalWatches: make(map[string]bool),
+               Events:          make(chan Event),
+               Errors:          make(chan error),
+               done:            make(chan bool),
+       }
+
+       go w.readEvents()
+       return w, nil
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+       w.mu.Lock()
+       if w.isClosed {
+               w.mu.Unlock()
+               return nil
+       }
+       w.isClosed = true
+       w.mu.Unlock()
+
+       // copy paths to remove while locked
+       w.mu.Lock()
+       var pathsToRemove = make([]string, 0, len(w.watches))
+       for name := range w.watches {
+               pathsToRemove = append(pathsToRemove, name)
+       }
+       w.mu.Unlock()
+       // unlock before calling Remove, which also locks
+
+       var err error
+       for _, name := range pathsToRemove {
+               if e := w.Remove(name); e != nil && err == nil {
+                       err = e
+               }
+       }
+
+       // Send "quit" message to the reader goroutine:
+       w.done <- true
+
+       return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+       w.mu.Lock()
+       w.externalWatches[name] = true
+       w.mu.Unlock()
+       _, err := w.addWatch(name, noteAllEvents)
+       return err
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+       name = filepath.Clean(name)
+       w.mu.Lock()
+       watchfd, ok := w.watches[name]
+       w.mu.Unlock()
+       if !ok {
+               return fmt.Errorf("can't remove non-existent kevent watch for: 
%s", name)
+       }
+
+       const registerRemove = unix.EV_DELETE
+       if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil 
{
+               return err
+       }
+
+       unix.Close(watchfd)
+
+       w.mu.Lock()
+       isDir := w.paths[watchfd].isDir
+       delete(w.watches, name)
+       delete(w.paths, watchfd)
+       delete(w.dirFlags, name)
+       w.mu.Unlock()
+
+       // Find all watched paths that are in this directory that are not 
external.
+       if isDir {
+               var pathsToRemove []string
+               w.mu.Lock()
+               for _, path := range w.paths {
+                       wdir, _ := filepath.Split(path.name)
+                       if filepath.Clean(wdir) == name {
+                               if !w.externalWatches[path.name] {
+                                       pathsToRemove = append(pathsToRemove, 
path.name)
+                               }
+                       }
+               }
+               w.mu.Unlock()
+               for _, name := range pathsToRemove {
+                       // Since these are internal, not much sense in 
propagating error
+                       // to the user, as that will just confuse them with an 
error about
+                       // a path they did not explicitly watch themselves.
+                       w.Remove(name)
+               }
+       }
+
+       return nil
+}
+
+// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
+const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | 
unix.NOTE_RENAME
+
+// keventWaitTime to block on each read from kevent
+var keventWaitTime = durationToTimespec(100 * time.Millisecond)
+
+// addWatch adds name to the watched file set.
+// The flags are interpreted as described in kevent(2).
+// Returns the real path to the file which was added, if any, which may be 
different from the one passed in the case of symlinks.
+func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
+       var isDir bool
+       // Make ./name and name equivalent
+       name = filepath.Clean(name)
+
+       w.mu.Lock()
+       if w.isClosed {
+               w.mu.Unlock()
+               return "", errors.New("kevent instance already closed")
+       }
+       watchfd, alreadyWatching := w.watches[name]
+       // We already have a watch, but we can still override flags.
+       if alreadyWatching {
+               isDir = w.paths[watchfd].isDir
+       }
+       w.mu.Unlock()
+
+       if !alreadyWatching {
+               fi, err := os.Lstat(name)
+               if err != nil {
+                       return "", err
+               }
+
+               // Don't watch sockets.
+               if fi.Mode()&os.ModeSocket == os.ModeSocket {
+                       return "", nil
+               }
+
+               // Don't watch named pipes.
+               if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
+                       return "", nil
+               }
+
+               // Follow Symlinks
+               // Unfortunately, Linux can add bogus symlinks to watch list 
without
+               // issue, and Windows can't do symlinks period (AFAIK). To  
maintain
+               // consistency, we will act like everything is fine. There will 
simply
+               // be no file events for broken symlinks.
+               // Hence the returns of nil on errors.
+               if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
+                       name, err = filepath.EvalSymlinks(name)
+                       if err != nil {
+                               return "", nil
+                       }
+
+                       w.mu.Lock()
+                       _, alreadyWatching = w.watches[name]
+                       w.mu.Unlock()
+
+                       if alreadyWatching {
+                               return name, nil
+                       }
+
+                       fi, err = os.Lstat(name)
+                       if err != nil {
+                               return "", nil
+                       }
+               }
+
+               watchfd, err = unix.Open(name, openMode, 0700)
+               if watchfd == -1 {
+                       return "", err
+               }
+
+               isDir = fi.IsDir()
+       }
+
+       const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
+       if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != 
nil {
+               unix.Close(watchfd)
+               return "", err
+       }
+
+       if !alreadyWatching {
+               w.mu.Lock()
+               w.watches[name] = watchfd
+               w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
+               w.mu.Unlock()
+       }
+
+       if isDir {
+               // Watch the directory if it has not been watched before,
+               // or if it was watched before, but perhaps only a NOTE_DELETE 
(watchDirectoryFiles)
+               w.mu.Lock()
+
+               watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
+                       (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) 
!= unix.NOTE_WRITE)
+               // Store flags so this watch can be updated later
+               w.dirFlags[name] = flags
+               w.mu.Unlock()
+
+               if watchDir {
+                       if err := w.watchDirectoryFiles(name); err != nil {
+                               return "", err
+                       }
+               }
+       }
+       return name, nil
+}
+
+// readEvents reads from kqueue and converts the received kevents into
+// Event values that it sends down the Events channel.
+func (w *Watcher) readEvents() {
+       eventBuffer := make([]unix.Kevent_t, 10)
+
+       for {
+               // See if there is a message on the "done" channel
+               select {
+               case <-w.done:
+                       err := unix.Close(w.kq)
+                       if err != nil {
+                               w.Errors <- err
+                       }
+                       close(w.Events)
+                       close(w.Errors)
+                       return
+               default:
+               }
+
+               // Get new events
+               kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
+               // EINTR is okay, the syscall was interrupted before timeout 
expired.
+               if err != nil && err != unix.EINTR {
+                       w.Errors <- err
+                       continue
+               }
+
+               // Flush the events we received to the Events channel
+               for len(kevents) > 0 {
+                       kevent := &kevents[0]
+                       watchfd := int(kevent.Ident)
+                       mask := uint32(kevent.Fflags)
+                       w.mu.Lock()
+                       path := w.paths[watchfd]
+                       w.mu.Unlock()
+                       event := newEvent(path.name, mask)
+
+                       if path.isDir && !(event.Op&Remove == Remove) {
+                               // Double check to make sure the directory 
exists. This can happen when
+                               // we do a rm -fr on a recursively watched 
folders and we receive a
+                               // modification event first but the folder has 
been deleted and later
+                               // receive the delete event
+                               if _, err := os.Lstat(event.Name); 
os.IsNotExist(err) {
+                                       // mark is as delete event
+                                       event.Op |= Remove
+                               }
+                       }
+
+                       if event.Op&Rename == Rename || event.Op&Remove == 
Remove {
+                               w.Remove(event.Name)
+                               w.mu.Lock()
+                               delete(w.fileExists, event.Name)
+                               w.mu.Unlock()
+                       }
+
+                       if path.isDir && event.Op&Write == Write && 
!(event.Op&Remove == Remove) {
+                               w.sendDirectoryChangeEvents(event.Name)
+                       } else {
+                               // Send the event on the Events channel
+                               w.Events <- event
+                       }
+
+                       if event.Op&Remove == Remove {
+                               // Look for a file that may have overwritten 
this.
+                               // For example, mv f1 f2 will delete f2, then 
create f2.
+                               if path.isDir {
+                                       fileDir := filepath.Clean(event.Name)
+                                       w.mu.Lock()
+                                       _, found := w.watches[fileDir]
+                                       w.mu.Unlock()
+                                       if found {
+                                               // make sure the directory 
exists before we watch for changes. When we
+                                               // do a recursive watch and 
perform rm -fr, the parent directory might
+                                               // have gone missing, ignore 
the missing directory and let the
+                                               // upcoming delete event remove 
the watch from the parent directory.
+                                               if _, err := os.Lstat(fileDir); 
err == nil {
+                                                       
w.sendDirectoryChangeEvents(fileDir)
+                                               }
+                                       }
+                               } else {
+                                       filePath := filepath.Clean(event.Name)
+                                       if fileInfo, err := os.Lstat(filePath); 
err == nil {
+                                               
w.sendFileCreatedEventIfNew(filePath, fileInfo)
+                                       }
+                               }
+                       }
+
+                       // Move to next event
+                       kevents = kevents[1:]
+               }
+       }
+}
+
+// newEvent returns an platform-independent Event based on kqueue Fflags.
+func newEvent(name string, mask uint32) Event {
+       e := Event{Name: name}
+       if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
+               e.Op |= Remove
+       }
+       if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
+               e.Op |= Write
+       }
+       if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
+               e.Op |= Rename
+       }
+       if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
+               e.Op |= Chmod
+       }
+       return e
+}
+
+func newCreateEvent(name string) Event {
+       return Event{Name: name, Op: Create}
+}
+
+// watchDirectoryFiles to mimic inotify when adding a watch on a directory
+func (w *Watcher) watchDirectoryFiles(dirPath string) error {
+       // Get all files
+       files, err := ioutil.ReadDir(dirPath)
+       if err != nil {
+               return err
+       }
+
+       for _, fileInfo := range files {
+               filePath := filepath.Join(dirPath, fileInfo.Name())
+               filePath, err = w.internalWatch(filePath, fileInfo)
+               if err != nil {
+                       return err
+               }
+
+               w.mu.Lock()
+               w.fileExists[filePath] = true
+               w.mu.Unlock()
+       }
+
+       return nil
+}
+
+// sendDirectoryEvents searches the directory for newly created files
+// and sends them over the event channel. This functionality is to have
+// the BSD version of fsnotify match Linux inotify which provides a
+// create event for files created in a watched directory.
+func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
+       // Get all files
+       files, err := ioutil.ReadDir(dirPath)
+       if err != nil {
+               w.Errors <- err
+       }
+
+       // Search for new files
+       for _, fileInfo := range files {
+               filePath := filepath.Join(dirPath, fileInfo.Name())
+               err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
+
+               if err != nil {
+                       return
+               }
+       }
+}
+
+// sendFileCreatedEvent sends a create event if the file isn't already being 
tracked.
+func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo 
os.FileInfo) (err error) {
+       w.mu.Lock()
+       _, doesExist := w.fileExists[filePath]
+       w.mu.Unlock()
+       if !doesExist {
+               // Send create event
+               w.Events <- newCreateEvent(filePath)
+       }
+
+       // like watchDirectoryFiles (but without doing another ReadDir)
+       filePath, err = w.internalWatch(filePath, fileInfo)
+       if err != nil {
+               return err
+       }
+
+       w.mu.Lock()
+       w.fileExists[filePath] = true
+       w.mu.Unlock()
+
+       return nil
+}
+
+func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, 
error) {
+       if fileInfo.IsDir() {
+               // mimic Linux providing delete events for subdirectories
+               // but preserve the flags used if currently watching 
subdirectory
+               w.mu.Lock()
+               flags := w.dirFlags[name]
+               w.mu.Unlock()
+
+               flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
+               return w.addWatch(name, flags)
+       }
+
+       // watch file to mimic Linux inotify
+       return w.addWatch(name, noteAllEvents)
+}
+
+// kqueue creates a new kernel event queue and returns a descriptor.
+func kqueue() (kq int, err error) {
+       kq, err = unix.Kqueue()
+       if kq == -1 {
+               return kq, err
+       }
+       return kq, nil
+}
+
+// register events with the queue
+func register(kq int, fds []int, flags int, fflags uint32) error {
+       changes := make([]unix.Kevent_t, len(fds))
+
+       for i, fd := range fds {
+               // SetKevent converts int to the platform-specific types:
+               unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
+               changes[i].Fflags = fflags
+       }
+
+       // register the events
+       success, err := unix.Kevent(kq, changes, nil, nil)
+       if success == -1 {
+               return err
+       }
+       return nil
+}
+
+// read retrieves pending events, or waits until an event occurs.
+// A timeout of nil blocks indefinitely, while 0 polls the queue.
+func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) 
([]unix.Kevent_t, error) {
+       n, err := unix.Kevent(kq, nil, events, timeout)
+       if err != nil {
+               return nil, err
+       }
+       return events[0:n], nil
+}
+
+// durationToTimespec prepares a timeout value
+func durationToTimespec(d time.Duration) unix.Timespec {
+       return unix.NsecToTimespec(d.Nanoseconds())
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_bsd.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_bsd.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_bsd.go
new file mode 100644
index 0000000..7d8de14
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_bsd.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd openbsd netbsd dragonfly
+
+package fsnotify
+
+import "golang.org/x/sys/unix"
+
+const openMode = unix.O_NONBLOCK | unix.O_RDONLY

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_darwin.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_darwin.go 
b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_darwin.go
new file mode 100644
index 0000000..9139e17
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/open_mode_darwin.go
@@ -0,0 +1,12 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin
+
+package fsnotify
+
+import "golang.org/x/sys/unix"
+
+// note: this constant is not defined on BSD
+const openMode = unix.O_EVTONLY

Reply via email to