You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2017/01/30 15:29:11 UTC

[05/19] incubator-trafficcontrol git commit: Move TM2 to trafficcontrol/traffic_monitor_golang

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/threadsafe/polledcaches.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/threadsafe/polledcaches.go b/traffic_monitor_golang/traffic_monitor/threadsafe/polledcaches.go
new file mode 100644
index 0000000..1cd4c18
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/threadsafe/polledcaches.go
@@ -0,0 +1,147 @@
+package threadsafe
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"sync"
+
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/cache"
+	dsdata "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/deliveryservicedata"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/enum"
+)
+
+// UnpolledCaches is a structure containing a map of caches which have yet to be polled, which is threadsafe for multiple readers and one writer.
+// This could be made lock-free, if the performance was necessary
+type UnpolledCaches struct {
+	unpolledCaches *map[enum.CacheName]struct{}
+	allCaches      *map[enum.CacheName]struct{}
+	initialized    *bool
+	m              *sync.RWMutex
+}
+
+// NewUnpolledCaches returns a new UnpolledCaches object.
+func NewUnpolledCaches() UnpolledCaches {
+	b := false
+	return UnpolledCaches{
+		m:              &sync.RWMutex{},
+		unpolledCaches: &map[enum.CacheName]struct{}{},
+		allCaches:      &map[enum.CacheName]struct{}{},
+		initialized:    &b,
+	}
+}
+
+// UnpolledCaches returns a map of caches not yet polled. Callers MUST NOT modify. If mutation is necessary, copy the map
+func (t *UnpolledCaches) UnpolledCaches() map[enum.CacheName]struct{} {
+	t.m.RLock()
+	defer t.m.RUnlock()
+	return *t.unpolledCaches
+}
+
+// setUnpolledCaches sets the internal unpolled caches map. This is only safe for one thread of execution. This MUST NOT be called from multiple threads.
+func (t *UnpolledCaches) setUnpolledCaches(v map[enum.CacheName]struct{}) {
+	t.m.Lock()
+	*t.initialized = true
+	*t.unpolledCaches = v
+	t.m.Unlock()
+}
+
+// SetNewCaches takes a list of new caches, which may overlap with the existing caches, diffs them, removes any `unpolledCaches` which aren't in the new list, and sets the list of `polledCaches` (which is only used by this func) to the `newCaches`. This is threadsafe with one writer, along with `setUnpolledCaches`.
+func (t *UnpolledCaches) SetNewCaches(newCaches map[enum.CacheName]struct{}) {
+	unpolledCaches := copyCaches(t.UnpolledCaches())
+	allCaches := copyCaches(*t.allCaches) // not necessary to lock `allCaches`, as the single-writer is the only thing that accesses it.
+	for cache := range unpolledCaches {
+		if _, ok := newCaches[cache]; !ok {
+			delete(unpolledCaches, cache)
+		}
+	}
+	for cache := range allCaches {
+		if _, ok := newCaches[cache]; !ok {
+			delete(allCaches, cache)
+		}
+	}
+	for cache := range newCaches {
+		if _, ok := allCaches[cache]; !ok {
+			unpolledCaches[cache] = struct{}{}
+			allCaches[cache] = struct{}{}
+		}
+	}
+	*t.allCaches = allCaches
+	t.setUnpolledCaches(unpolledCaches)
+}
+
+// Any returns whether there are any caches marked as not polled. Also returns true if SetNewCaches() has never been called (assuming there exist caches, if this hasn't been initialized, we couldn't have polled any of them).
+func (t *UnpolledCaches) Any() bool {
+	t.m.Lock()
+	defer t.m.Unlock()
+	return !(*t.initialized) || len(*t.unpolledCaches) > 0
+}
+
+// copyCaches performs a deep copy of the given map.
+func copyCaches(a map[enum.CacheName]struct{}) map[enum.CacheName]struct{} {
+	b := map[enum.CacheName]struct{}{}
+	for k := range a {
+		b[k] = struct{}{}
+	}
+	return b
+}
+
+// SetPolled sets cache which have been polled. This is used to determine when the app has fully started up, and we can start serving. Serving Traffic Router with caches as 'down' which simply haven't been polled yet would be bad. Therefore, a cache is set as 'polled' if it has received different bandwidths from two different ATS ticks, OR if the cache is marked as down (and thus we won't get a bandwidth).
+// This is threadsafe for one writer, along with `Set`.
+// This is fast if there are no unpolled caches. Moreover, its speed is a function of the number of unpolled caches, not the number of caches total.
+func (t *UnpolledCaches) SetPolled(results []cache.Result, lastStats dsdata.LastStats) {
+	unpolledCaches := copyCaches(t.UnpolledCaches())
+	numUnpolledCaches := len(unpolledCaches)
+	if numUnpolledCaches == 0 {
+		return
+	}
+	for cache := range unpolledCaches {
+	innerLoop:
+		for _, result := range results {
+			if result.ID != cache {
+				continue
+			}
+
+			if !result.Available || result.Error != nil {
+				log.Debugf("polled %v\n", cache)
+				delete(unpolledCaches, cache)
+				break innerLoop
+			}
+		}
+		lastStat, ok := lastStats.Caches[cache]
+		if !ok {
+			continue
+		}
+		if lastStat.Bytes.PerSec != 0 {
+			log.Debugf("polled %v\n", cache)
+			delete(unpolledCaches, cache)
+		}
+	}
+
+	if len(unpolledCaches) == numUnpolledCaches {
+		return
+	}
+	t.setUnpolledCaches(unpolledCaches)
+	if len(unpolledCaches) != 0 {
+		log.Infof("remaining unpolled %v\n", unpolledCaches)
+	} else {
+		log.Infof("all caches polled, ready to serve!\n")
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/threadsafe/resulthistory.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/threadsafe/resulthistory.go b/traffic_monitor_golang/traffic_monitor/threadsafe/resulthistory.go
new file mode 100644
index 0000000..320aabf
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/threadsafe/resulthistory.go
@@ -0,0 +1,54 @@
+package threadsafe
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"sync"
+
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/cache"
+)
+
+// ResultHistory provides safe access for multiple goroutines readers and a single writer to a stored ResultHistory object.
+// This could be made lock-free, if the performance was necessary
+// TODO add separate locks for Caches and Deliveryservice maps?
+type ResultHistory struct {
+	resultHistory *cache.ResultHistory
+	m             *sync.RWMutex
+}
+
+// NewResultHistory returns a new ResultHistory safe for multiple readers and a single writer.
+func NewResultHistory() ResultHistory {
+	h := cache.ResultHistory{}
+	return ResultHistory{m: &sync.RWMutex{}, resultHistory: &h}
+}
+
+// Get returns the ResultHistory. Callers MUST NOT modify. If mutation is necessary, call ResultHistory.Copy()
+func (h *ResultHistory) Get() cache.ResultHistory {
+	h.m.RLock()
+	defer h.m.RUnlock()
+	return *h.resultHistory
+}
+
+// Set sets the internal ResultHistory. This is only safe for one thread of execution. This MUST NOT be called from multiple threads.
+func (h *ResultHistory) Set(v cache.ResultHistory) {
+	h.m.Lock()
+	*h.resultHistory = v
+	h.m.Unlock()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/threadsafe/resultstathistory.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/threadsafe/resultstathistory.go b/traffic_monitor_golang/traffic_monitor/threadsafe/resultstathistory.go
new file mode 100644
index 0000000..6ea76b0
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/threadsafe/resultstathistory.go
@@ -0,0 +1,81 @@
+// TODO rename
+package threadsafe
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"sync"
+
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/cache"
+)
+
+// ResultStatHistory provides safe access for multiple goroutines readers and a single writer to a stored HistoryHistory object.
+// This could be made lock-free, if the performance was necessary
+type ResultStatHistory struct {
+	history *cache.ResultStatHistory
+	m       *sync.RWMutex
+}
+
+// NewResultStatHistory returns a new ResultStatHistory safe for multiple readers and a single writer.
+func NewResultStatHistory() ResultStatHistory {
+	h := cache.ResultStatHistory{}
+	return ResultStatHistory{m: &sync.RWMutex{}, history: &h}
+}
+
+// Get returns the ResultStatHistory. Callers MUST NOT modify. If mutation is necessary, call ResultStatHistory.Copy()
+func (h *ResultStatHistory) Get() cache.ResultStatHistory {
+	h.m.RLock()
+	defer h.m.RUnlock()
+	return *h.history
+}
+
+// Set sets the internal ResultStatHistory. This is only safe for one thread of execution. This MUST NOT be called from multiple threads.
+func (h *ResultStatHistory) Set(v cache.ResultStatHistory) {
+	h.m.Lock()
+	*h.history = v
+	h.m.Unlock()
+}
+
+// ResultStatHistory provides safe access for multiple goroutines readers and a single writer to a stored HistoryHistory object.
+// This could be made lock-free, if the performance was necessary
+type ResultInfoHistory struct {
+	history *cache.ResultInfoHistory
+	m       *sync.RWMutex
+}
+
+// NewResultInfoHistory returns a new ResultInfoHistory safe for multiple readers and a single writer.
+func NewResultInfoHistory() ResultInfoHistory {
+	h := cache.ResultInfoHistory{}
+	return ResultInfoHistory{m: &sync.RWMutex{}, history: &h}
+}
+
+// Get returns the ResultInfoHistory. Callers MUST NOT modify. If mutation is necessary, call ResultInfoHistory.Copy()
+func (h *ResultInfoHistory) Get() cache.ResultInfoHistory {
+	h.m.RLock()
+	defer h.m.RUnlock()
+	return *h.history
+}
+
+// Set sets the internal ResultInfoHistory. This is only safe for one thread of execution. This MUST NOT be called from multiple threads.
+func (h *ResultInfoHistory) Set(v cache.ResultInfoHistory) {
+	h.m.Lock()
+	*h.history = v
+	h.m.Unlock()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/threadsafe/uint.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/threadsafe/uint.go b/traffic_monitor_golang/traffic_monitor/threadsafe/uint.go
new file mode 100644
index 0000000..fcaa3a4
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/threadsafe/uint.go
@@ -0,0 +1,51 @@
+package threadsafe
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"sync/atomic"
+)
+
+// Uint provides safe access for multiple goroutines readers and a single writer to a stored uint.
+type Uint struct {
+	val *uint64
+}
+
+// NewUint returns a new single-writer-multiple-reader threadsafe uint
+func NewUint() Uint {
+	v := uint64(0)
+	return Uint{val: &v}
+}
+
+// Get gets the internal uint. This is safe for multiple readers
+func (u *Uint) Get() uint64 {
+	return atomic.LoadUint64(u.val)
+}
+
+// Set sets the internal uint. This MUST NOT be called by multiple goroutines.
+func (u *Uint) Set(v uint64) {
+	atomic.StoreUint64(u.val, v)
+}
+
+// Inc increments the internal uint64.
+// TODO make sure everything using this uses the value it returns, not a separate Get
+func (u *Uint) Inc() uint64 {
+	return atomic.AddUint64(u.val, 1)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/traffic_monitor.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/traffic_monitor.go b/traffic_monitor_golang/traffic_monitor/traffic_monitor.go
new file mode 100644
index 0000000..d77b628
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/traffic_monitor.go
@@ -0,0 +1,157 @@
+package main
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"os/exec"
+	"runtime"
+	"time"
+
+	_ "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/instrumentation"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/config"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/manager"
+	_ "github.com/davecheney/gmx"
+)
+
+// GitRevision is the git revision of the app. The app SHOULD always be built with this set via the `-X` flag.
+var GitRevision = "No Git Revision Specified. Please build with '-X main.GitRevision=${git rev-parse HEAD}'"
+
+// BuildTimestamp is the time the app was built. The app SHOULD always be built with this set via the `-X` flag.
+var BuildTimestamp = "No Build Timestamp Specified. Please build with '-X main.BuildTimestamp=`date +'%Y-%M-%dT%H:%M:%S'`"
+
+// getHostNameWithoutDomain returns the machine hostname, without domain information.
+// Modified from http://stackoverflow.com/a/34331660/292623
+func getHostNameWithoutDomain() (string, error) {
+	cmd := exec.Command("/bin/hostname", "-s")
+	var out bytes.Buffer
+	cmd.Stdout = &out
+	err := cmd.Run()
+	if err != nil {
+		return "", err
+	}
+	hostname := out.String()
+	if len(hostname) < 1 {
+		return "", fmt.Errorf("OS returned empty hostname")
+	}
+	hostname = hostname[:len(hostname)-1] // removing EOL
+	return hostname, nil
+}
+
+// getStaticAppData returns app data available at start time.
+// This should be called immediately, as it includes calculating when the app was started.
+func getStaticAppData() (manager.StaticAppData, error) {
+	var d manager.StaticAppData
+	var err error
+	d.StartTime = time.Now()
+	d.GitRevision = GitRevision
+	d.FreeMemoryMB = math.MaxUint64 // TODO remove if/when nothing needs this
+	d.Version = Version
+	if d.WorkingDir, err = os.Getwd(); err != nil {
+		return manager.StaticAppData{}, err
+	}
+	d.Name = os.Args[0]
+	d.BuildTimestamp = BuildTimestamp
+	if d.Hostname, err = getHostNameWithoutDomain(); err != nil {
+		return manager.StaticAppData{}, err
+	}
+
+	return d, nil
+}
+
+func getLogWriter(location string) (io.Writer, error) {
+	switch location {
+	case config.LogLocationStdout:
+		return os.Stdout, nil
+	case config.LogLocationStderr:
+		return os.Stderr, nil
+	case config.LogLocationNull:
+		return ioutil.Discard, nil
+	default:
+		return os.OpenFile(location, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
+	}
+}
+func getLogWriters(eventLoc, errLoc, warnLoc, infoLoc, debugLoc string) (io.Writer, io.Writer, io.Writer, io.Writer, io.Writer, error) {
+	eventW, err := getLogWriter(eventLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log event writer %v: %v", eventLoc, err)
+	}
+	errW, err := getLogWriter(errLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log error writer %v: %v", errLoc, err)
+	}
+	warnW, err := getLogWriter(warnLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log warning writer %v: %v", warnLoc, err)
+	}
+	infoW, err := getLogWriter(infoLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log info writer %v: %v", infoLoc, err)
+	}
+	debugW, err := getLogWriter(debugLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log debug writer %v: %v", debugLoc, err)
+	}
+	return eventW, errW, warnW, infoW, debugW, nil
+}
+
+func main() {
+	runtime.GOMAXPROCS(runtime.NumCPU())
+
+	staticData, err := getStaticAppData()
+	if err != nil {
+		fmt.Printf("Error starting service: failed to get static app data: %v\n", err)
+		os.Exit(1)
+	}
+
+	opsConfigFile := flag.String("opsCfg", "", "The traffic ops config file")
+	configFileName := flag.String("config", "", "The Traffic Monitor config file path")
+	flag.Parse()
+
+	if *opsConfigFile == "" {
+		fmt.Println("Error starting service: The --opsCfg argument is required")
+		os.Exit(1)
+	}
+
+	// TODO add hot reloading (like opsConfigFile)?
+	cfg, err := config.Load(*configFileName)
+	if err != nil {
+		fmt.Printf("Error starting service: failed to load config: %v\n", err)
+		os.Exit(1)
+	}
+
+	eventW, errW, warnW, infoW, debugW, err := getLogWriters(cfg.LogLocationEvent, cfg.LogLocationError, cfg.LogLocationWarning, cfg.LogLocationInfo, cfg.LogLocationDebug)
+	if err != nil {
+		fmt.Printf("Error starting service: failed to create log writers: %v\n", err)
+		os.Exit(1)
+	}
+	log.Init(eventW, errW, warnW, infoW, debugW)
+
+	log.Infof("Starting with config %+v\n", cfg)
+
+	manager.Start(*opsConfigFile, cfg, staticData)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/trafficopsdata/trafficopsdata.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/trafficopsdata/trafficopsdata.go b/traffic_monitor_golang/traffic_monitor/trafficopsdata/trafficopsdata.go
new file mode 100644
index 0000000..69c7af1
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/trafficopsdata/trafficopsdata.go
@@ -0,0 +1,290 @@
+package trafficopsdata
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/enum"
+	towrap "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/trafficopswrapper"
+	"regexp"
+	"strings"
+	"sync"
+)
+
+// Regexes maps Delivery Service Regular Expressions to delivery services.
+// For performance, we categorize Regular Expressions into 3 categories:
+// 1. Direct string matches, with no regular expression matching characters
+// 2. .*\.foo\..* expressions, where foo is a direct string match with no regular expression matching characters
+// 3. Everything else
+// This allows us to do a cheap match on 1 and 2, and only regex match the uncommon case.
+// TODO performance tests, whether Go compiled *Regexp is relevantly slower than `strings.Contains` for direct and .foo. matches
+type Regexes struct {
+	DirectMatches                      map[string]enum.DeliveryServiceName
+	DotStartSlashDotFooSlashDotDotStar map[string]enum.DeliveryServiceName
+	RegexMatch                         map[*regexp.Regexp]enum.DeliveryServiceName
+}
+
+// DeliveryService returns the delivery service which matches the given fqdn, or false.
+func (d Regexes) DeliveryService(fqdn string) (enum.DeliveryServiceName, bool) {
+	if ds, ok := d.DirectMatches[fqdn]; ok {
+		return ds, true
+	}
+	for matchStr, ds := range d.DotStartSlashDotFooSlashDotDotStar {
+		if strings.Contains(fqdn, "."+matchStr+".") {
+			return ds, true
+		}
+	}
+	for regex, ds := range d.RegexMatch {
+		if regex.MatchString(fqdn) {
+			return ds, true
+		}
+	}
+	return "", false
+}
+
+// NewRegexes constructs a new Regexes object, initializing internal pointer members.
+func NewRegexes() Regexes {
+	return Regexes{DirectMatches: map[string]enum.DeliveryServiceName{}, DotStartSlashDotFooSlashDotDotStar: map[string]enum.DeliveryServiceName{}, RegexMatch: map[*regexp.Regexp]enum.DeliveryServiceName{}}
+}
+
+// TOData holds CDN data fetched from Traffic Ops.
+type TOData struct {
+	DeliveryServiceServers map[enum.DeliveryServiceName][]enum.CacheName
+	ServerDeliveryServices map[enum.CacheName][]enum.DeliveryServiceName
+	ServerTypes            map[enum.CacheName]enum.CacheType
+	DeliveryServiceTypes   map[enum.DeliveryServiceName]enum.DSType
+	DeliveryServiceRegexes Regexes
+	ServerCachegroups      map[enum.CacheName]enum.CacheGroupName
+}
+
+// New returns a new empty TOData object, initializing pointer members.
+func New() *TOData {
+	return &TOData{
+		DeliveryServiceServers: map[enum.DeliveryServiceName][]enum.CacheName{},
+		ServerDeliveryServices: map[enum.CacheName][]enum.DeliveryServiceName{},
+		ServerTypes:            map[enum.CacheName]enum.CacheType{},
+		DeliveryServiceTypes:   map[enum.DeliveryServiceName]enum.DSType{},
+		DeliveryServiceRegexes: NewRegexes(),
+		ServerCachegroups:      map[enum.CacheName]enum.CacheGroupName{},
+	}
+}
+
+// TODataThreadsafe provides safe access for multiple goroutine writers and one goroutine reader, to the encapsulated TOData object.
+// This could be made lock-free, if the performance was necessary
+type TODataThreadsafe struct {
+	toData *TOData
+	m      *sync.RWMutex
+}
+
+// NewThreadsafe returns a new TOData object, wrapped to be safe for multiple goroutine readers and a single writer.
+func NewThreadsafe() TODataThreadsafe {
+	return TODataThreadsafe{m: &sync.RWMutex{}, toData: New()}
+}
+
+// Get returns the current TOData. Callers MUST NOT modify returned data. Mutation IS NOT threadsafe
+// If callers need to modify, a new GetMutable() should be added which copies.
+func (d TODataThreadsafe) Get() TOData {
+	d.m.RLock()
+	defer d.m.RUnlock()
+	return *d.toData
+}
+
+func (d TODataThreadsafe) set(newTOData TOData) {
+	d.m.Lock()
+	*d.toData = newTOData
+	d.m.Unlock()
+}
+
+// CRConfig is the CrConfig data needed by TOData. Note this is not all data in the CRConfig.
+// TODO change strings to type?
+type CRConfig struct {
+	ContentServers map[enum.CacheName]struct {
+		DeliveryServices map[enum.DeliveryServiceName][]string `json:"deliveryServices"`
+		CacheGroup       string                                `json:"cacheGroup"`
+		Type             string                                `json:"type"`
+	} `json:"contentServers"`
+	DeliveryServices map[enum.DeliveryServiceName]struct {
+		Matchsets []struct {
+			Protocol  string `json:"protocol"`
+			MatchList []struct {
+				Regex string `json:"regex"`
+			} `json:"matchlist"`
+		} `json:"matchsets"`
+	} `json:"deliveryServices"`
+}
+
+// Fetch gets the CRConfig from Traffic Ops, creates the TOData maps, and atomically sets the TOData.
+// TODO since the session is threadsafe, each TOData get func below could be put in a goroutine, if performance mattered
+func (d TODataThreadsafe) Fetch(to towrap.ITrafficOpsSession, cdn string) error {
+	newTOData := TOData{}
+
+	crConfigBytes, err := to.CRConfigRaw(cdn)
+	if err != nil {
+		return fmt.Errorf("Error getting CRconfig from Traffic Ops: %v", err)
+	}
+	var crConfig CRConfig
+	err = json.Unmarshal(crConfigBytes, &crConfig)
+	if err != nil {
+		return fmt.Errorf("Error unmarshalling CRconfig: %v", err)
+	}
+
+	newTOData.DeliveryServiceServers, newTOData.ServerDeliveryServices, err = getDeliveryServiceServers(crConfig)
+	if err != nil {
+		return err
+	}
+
+	newTOData.DeliveryServiceTypes, err = getDeliveryServiceTypes(crConfig)
+	if err != nil {
+		return fmt.Errorf("Error getting delivery service types from Traffic Ops: %v\n", err)
+	}
+
+	newTOData.DeliveryServiceRegexes, err = getDeliveryServiceRegexes(crConfig)
+	if err != nil {
+		return fmt.Errorf("Error getting delivery service regexes from Traffic Ops: %v\n", err)
+	}
+
+	newTOData.ServerCachegroups, err = getServerCachegroups(crConfig)
+	if err != nil {
+		return fmt.Errorf("Error getting server cachegroups from Traffic Ops: %v\n", err)
+	}
+
+	newTOData.ServerTypes, err = getServerTypes(crConfig)
+	if err != nil {
+		return fmt.Errorf("Error getting server types from Traffic Ops: %v\n", err)
+	}
+
+	d.set(newTOData)
+	return nil
+}
+
+// getDeliveryServiceServers gets the servers on each delivery services, for the given CDN, from Traffic Ops.
+func getDeliveryServiceServers(crc CRConfig) (map[enum.DeliveryServiceName][]enum.CacheName, map[enum.CacheName][]enum.DeliveryServiceName, error) {
+	dsServers := map[enum.DeliveryServiceName][]enum.CacheName{}
+	serverDses := map[enum.CacheName][]enum.DeliveryServiceName{}
+
+	for serverName, serverData := range crc.ContentServers {
+		for deliveryServiceName := range serverData.DeliveryServices {
+			dsServers[deliveryServiceName] = append(dsServers[deliveryServiceName], serverName)
+			serverDses[serverName] = append(serverDses[serverName], deliveryServiceName)
+		}
+	}
+	return dsServers, serverDses, nil
+}
+
+// getDeliveryServiceRegexes gets the regexes of each delivery service, for the given CDN, from Traffic Ops.
+// Returns a map[deliveryService][]regex.
+func getDeliveryServiceRegexes(crc CRConfig) (Regexes, error) {
+	dsRegexes := map[enum.DeliveryServiceName][]string{}
+
+	for dsName, dsData := range crc.DeliveryServices {
+		if len(dsData.Matchsets) < 1 {
+			return Regexes{}, fmt.Errorf("CRConfig missing regex for '%s'", dsName)
+		}
+		for _, matchset := range dsData.Matchsets {
+			if len(matchset.MatchList) < 1 {
+				return Regexes{}, fmt.Errorf("CRConfig missing Regex for '%s'", dsName)
+			}
+			dsRegexes[dsName] = append(dsRegexes[dsName], matchset.MatchList[0].Regex)
+		}
+	}
+
+	return createRegexes(dsRegexes)
+}
+
+// TODO precompute, move to TOData; call when we get new delivery services, instead of every time we create new stats
+func createRegexes(dsToRegex map[enum.DeliveryServiceName][]string) (Regexes, error) {
+	dsRegexes := Regexes{
+		DirectMatches:                      map[string]enum.DeliveryServiceName{},
+		DotStartSlashDotFooSlashDotDotStar: map[string]enum.DeliveryServiceName{},
+		RegexMatch:                         map[*regexp.Regexp]enum.DeliveryServiceName{},
+	}
+
+	for ds, regexStrs := range dsToRegex {
+		for _, regexStr := range regexStrs {
+			prefix := `.*\.`
+			suffix := `\..*`
+			if strings.HasPrefix(regexStr, prefix) && strings.HasSuffix(regexStr, suffix) {
+				matchStr := regexStr[len(prefix) : len(regexStr)-len(suffix)]
+				if otherDs, ok := dsRegexes.DotStartSlashDotFooSlashDotDotStar[matchStr]; ok {
+					return dsRegexes, fmt.Errorf("duplicate regex %s (%s) in %s and %s", regexStr, matchStr, ds, otherDs)
+				}
+				dsRegexes.DotStartSlashDotFooSlashDotDotStar[matchStr] = ds
+				continue
+			}
+			if !strings.ContainsAny(regexStr, `[]^\:{}()|?+*,=%@<>!'`) {
+				if otherDs, ok := dsRegexes.DirectMatches[regexStr]; ok {
+					return dsRegexes, fmt.Errorf("duplicate Regex %s in %s and %s", regexStr, ds, otherDs)
+				}
+				dsRegexes.DirectMatches[regexStr] = ds
+				continue
+			}
+			// TODO warn? regex matches are unusual
+			r, err := regexp.Compile(regexStr)
+			if err != nil {
+				return dsRegexes, fmt.Errorf("regex %s failed to compile: %v", regexStr, err)
+			}
+			dsRegexes.RegexMatch[r] = ds
+		}
+	}
+	return dsRegexes, nil
+}
+
+// getServerCachegroups gets the cachegroup of each ATS Edge+Mid Cache server, for the given CDN, from Traffic Ops.
+// Returns a map[server]cachegroup.
+func getServerCachegroups(crc CRConfig) (map[enum.CacheName]enum.CacheGroupName, error) {
+	serverCachegroups := map[enum.CacheName]enum.CacheGroupName{}
+
+	for server, serverData := range crc.ContentServers {
+		serverCachegroups[server] = enum.CacheGroupName(serverData.CacheGroup)
+	}
+	return serverCachegroups, nil
+}
+
+// getServerTypes gets the cache type of each ATS Edge+Mid Cache server, for the given CDN, from Traffic Ops.
+func getServerTypes(crc CRConfig) (map[enum.CacheName]enum.CacheType, error) {
+	serverTypes := map[enum.CacheName]enum.CacheType{}
+
+	for server, serverData := range crc.ContentServers {
+		t := enum.CacheTypeFromString(serverData.Type)
+		if t == enum.CacheTypeInvalid {
+			return nil, fmt.Errorf("getServerTypes CRConfig unknown type for '%s': '%s'", server, serverData.Type)
+		}
+		serverTypes[server] = t
+	}
+	return serverTypes, nil
+}
+
+func getDeliveryServiceTypes(crc CRConfig) (map[enum.DeliveryServiceName]enum.DSType, error) {
+	dsTypes := map[enum.DeliveryServiceName]enum.DSType{}
+
+	for dsName, dsData := range crc.DeliveryServices {
+		if len(dsData.Matchsets) < 1 {
+			return nil, fmt.Errorf("CRConfig missing protocol for '%s'", dsName)
+		}
+		dsTypeStr := dsData.Matchsets[0].Protocol
+		dsType := enum.DSTypeFromString(dsTypeStr)
+		if dsType == enum.DSTypeInvalid {
+			return nil, fmt.Errorf("CRConfig unknowng protocol for '%s': '%s'", dsName, dsTypeStr)
+		}
+		dsTypes[dsName] = dsType
+	}
+	return dsTypes, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/trafficopswrapper/trafficopswrapper.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/trafficopswrapper/trafficopswrapper.go b/traffic_monitor_golang/traffic_monitor/trafficopswrapper/trafficopswrapper.go
new file mode 100644
index 0000000..3c48543
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/trafficopswrapper/trafficopswrapper.go
@@ -0,0 +1,128 @@
+package trafficopswrapper
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"fmt"
+	"sync"
+
+	to "github.com/apache/incubator-trafficcontrol/traffic_ops/client"
+)
+
+// ITrafficOpsSession provides an interface to the Traffic Ops client, so it may be wrapped or mocked.
+type ITrafficOpsSession interface {
+	CRConfigRaw(cdn string) ([]byte, error)
+	TrafficMonitorConfigMap(cdn string) (*to.TrafficMonitorConfigMap, error)
+	Set(session *to.Session)
+	URL() (string, error)
+	User() (string, error)
+	Servers() ([]to.Server, error)
+	Parameters(profileName string) ([]to.Parameter, error)
+	DeliveryServices() ([]to.DeliveryService, error)
+}
+
+var ErrNilSession = fmt.Errorf("nil session")
+
+func (s TrafficOpsSessionThreadsafe) URL() (string, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return "", ErrNilSession
+	}
+	url := (*s.session).URL
+	return url, nil
+}
+
+func (s TrafficOpsSessionThreadsafe) User() (string, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return "", ErrNilSession
+	}
+	user := (*s.session).UserName
+	return user, nil
+}
+
+// TrafficOpsSessionThreadsafe provides access to the Traffic Ops client safe for multiple goroutines. This fulfills the ITrafficOpsSession interface.
+type TrafficOpsSessionThreadsafe struct {
+	session **to.Session // pointer-to-pointer, because we're given a pointer from the Traffic Ops package, and we don't want to copy it.
+	m       *sync.Mutex
+}
+
+// NewTrafficOpsSessionThreadsafe returns a new threadsafe TrafficOpsSessionThreadsafe wrapping the given `Session`.
+func NewTrafficOpsSessionThreadsafe(s *to.Session) TrafficOpsSessionThreadsafe {
+	return TrafficOpsSessionThreadsafe{&s, &sync.Mutex{}}
+}
+
+// CRConfigRaw returns the CRConfig from the Traffic Ops. This is safe for multiple goroutines.
+func (s TrafficOpsSessionThreadsafe) CRConfigRaw(cdn string) ([]byte, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return nil, ErrNilSession
+	}
+	b, _, e := (*s.session).GetCRConfig(cdn)
+	return b, e
+}
+
+// TrafficMonitorConfigMap returns the Traffic Monitor config map from the Traffic Ops. This is safe for multiple goroutines.
+func (s TrafficOpsSessionThreadsafe) TrafficMonitorConfigMap(cdn string) (*to.TrafficMonitorConfigMap, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return nil, ErrNilSession
+	}
+	d, e := (*s.session).TrafficMonitorConfigMap(cdn)
+	return d, e
+}
+
+// Set sets the internal Traffic Ops session. This is safe for multiple goroutines, being aware they will race.
+func (s TrafficOpsSessionThreadsafe) Set(session *to.Session) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	*s.session = session
+}
+
+func (s TrafficOpsSessionThreadsafe) Servers() ([]to.Server, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return nil, ErrNilSession
+	}
+	return (*s.session).Servers()
+}
+
+func (s TrafficOpsSessionThreadsafe) Parameters(profileName string) ([]to.Parameter, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return nil, ErrNilSession
+	}
+	return (*s.session).Parameters(profileName)
+}
+
+func (s TrafficOpsSessionThreadsafe) DeliveryServices() ([]to.DeliveryService, error) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	if s.session == nil || *s.session == nil {
+		return nil, ErrNilSession
+	}
+	return (*s.session).DeliveryServices()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/traffic_monitor/version.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/version.go b/traffic_monitor_golang/traffic_monitor/version.go
new file mode 100644
index 0000000..c1ecc0c
--- /dev/null
+++ b/traffic_monitor_golang/traffic_monitor/version.go
@@ -0,0 +1,23 @@
+package main
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Version is the current version of the app, in string form.
+var Version = "2.0.1"

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/.gitignore
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/.gitignore b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/.gitignore
new file mode 100644
index 0000000..19c3660
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/.gitignore
@@ -0,0 +1 @@
+gmxc/gmxc

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/LICENCE
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/LICENCE b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/LICENCE
new file mode 100644
index 0000000..d7f4f29
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/LICENCE
@@ -0,0 +1,8 @@
+Copyright (c) 2012, David Cheney
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/README.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/README.md b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/README.md
new file mode 100644
index 0000000..b66d10c
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/README.md
@@ -0,0 +1,52 @@
+# Go management extensions
+
+## Installation
+  
+	go get github.com/davecheney/gmx
+
+## Getting started
+
+Instrumenting your application with gmx is as simple as importing the `gmx` package in your `main` package via the side effect operator.
+
+	package main
+
+	import _ "github.com/davecheney/gmx"
+
+By default gmx opens a unix socket in `/tmp`, the name of the socket is
+
+	/tmp/.gmx.$PID.0
+
+## Protocol version 0
+
+The current protocol version is 0, which is a simple JSON based protocol. You can communicate with the gmx socket using a tool like socat.
+
+	% socat UNIX-CONNECT:/tmp/.gmx.$(pgrep godoc).0 stdin
+	["runtime.version", "runtime.numcpu"]
+	{"runtime.numcpu":4,"runtime.version":"weekly.2012-01-27 11688+"}
+     
+The request is a json array of strings representing keys that you wish to query. The result is a json map, the keys of that map are keys that matched the keys in your request. The value of the entry will be the result of the published function, encoded in json. If there is no matching key registered, no entry will appear in the result map.
+
+For convenience a client is included in the gmxc sub directory. Please consult the `README` in that directory for more details.
+
+## Registering gmx keys
+
+New keys can be registered using the `Publish` function
+
+	gmx.Publish(key string, f func() interface{})
+
+`f` can be any function that returns a json encodable result. `f` is executed whenever its key is invoked, responsibility for ensuring the function is thread safe rests with the author of `f`.
+
+## Runtime instrumentation
+
+By default gmx instruments selected values from the  `runtime` and `os` packages, refer to the `runtime.go` and `os.go` source for more details.
+
+## Changelog
+
+6/Feb/2012 
+
++	gmx now honors the value of os.TempDir() when opening the unix socket
++	gmxc now accepts regexps for key names
+
+5/Feb/2012 
+
++	Initial release

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/README.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/README.md b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/README.md
new file mode 100644
index 0000000..6cc9401
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/README.md
@@ -0,0 +1,19 @@
+# helloworld example
+
+Install the gmxc client
+
+	go get github.com/davecheney/gmx/gmxc
+
+Install this example 
+
+	go get github.com/davecheney/gmx/example/helloworld
+
+Run the example in the background
+
+	$GOBIN/helloworld &
+
+Query it via gmxc
+
+	$GOBIN/gmxc -p $(pgrep helloworld) hello
+	hello: world
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/main.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/main.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/main.go
new file mode 100644
index 0000000..f6d2765
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/example/helloworld/main.go
@@ -0,0 +1,14 @@
+package main
+
+import "github.com/davecheney/gmx"
+
+func init() {
+	gmx.Publish("hello", func() interface{} {
+		return "world"
+	})
+}
+
+func main() {
+	// sleep forever
+	select {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmx.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmx.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmx.go
new file mode 100644
index 0000000..5b446fc
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmx.go
@@ -0,0 +1,129 @@
+package gmx
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"sync"
+)
+
+const GMX_VERSION = 0
+
+var (
+	r = &registry{
+		entries: make(map[string]func() interface{}),
+	}
+)
+
+func init() {
+	s, err := localSocket()
+	if err != nil {
+		log.Printf("gmx: unable to open local socket: %v", err)
+		return
+	}
+
+	// register the registries keys for discovery
+	Publish("keys", func() interface{} {
+		return r.keys()
+	})
+	go serve(s, r)
+}
+
+func localSocket() (net.Listener, error) {
+	return net.ListenUnix("unix", localSocketAddr())
+}
+
+func localSocketAddr() *net.UnixAddr {
+	return &net.UnixAddr{
+		filepath.Join(os.TempDir(), fmt.Sprintf(".gmx.%d.%d", os.Getpid(), GMX_VERSION)),
+		"unix",
+	}
+}
+
+// Publish registers the function f with the supplied key.
+func Publish(key string, f func() interface{}) {
+	r.register(key, f)
+}
+
+func serve(l net.Listener, r *registry) {
+	// if listener is a unix socket, try to delete it on shutdown
+	if l, ok := l.(*net.UnixListener); ok {
+		if a, ok := l.Addr().(*net.UnixAddr); ok {
+			defer os.Remove(a.Name)
+		}
+	}
+	defer l.Close()
+	for {
+		c, err := l.Accept()
+		if err != nil {
+			return
+		}
+		go handle(c, r)
+	}
+}
+
+func handle(nc net.Conn, reg *registry) {
+	// conn makes it easier to send and receive json
+	type conn struct {
+		net.Conn
+		*json.Encoder
+		*json.Decoder
+	}
+	c := conn{
+		nc,
+		json.NewEncoder(nc),
+		json.NewDecoder(nc),
+	}
+	defer c.Close()
+	for {
+		var keys []string
+		if err := c.Decode(&keys); err != nil {
+			if err != io.EOF {
+				log.Printf("gmx: client %v sent invalid json request: %v", c.RemoteAddr(), err)
+			}
+			return
+		}
+		var result = make(map[string]interface{})
+		for _, key := range keys {
+			if f, ok := reg.value(key); ok {
+				// invoke the function for key and store the result
+				result[key] = f()
+			}
+		}
+		if err := c.Encode(result); err != nil {
+			log.Printf("gmx: could not send response to client %v: %v", c.RemoteAddr(), err)
+			return
+		}
+	}
+}
+
+type registry struct {
+	sync.Mutex // protects entries from concurrent mutation
+	entries    map[string]func() interface{}
+}
+
+func (r *registry) register(key string, f func() interface{}) {
+	r.Lock()
+	defer r.Unlock()
+	r.entries[key] = f
+}
+
+func (r *registry) value(key string) (func() interface{}, bool) {
+	r.Lock()
+	defer r.Unlock()
+	f, ok := r.entries[key]
+	return f, ok
+}
+
+func (r *registry) keys() (k []string) {
+	r.Lock()
+	defer r.Unlock()
+	for e := range r.entries {
+		k = append(k, e)
+	}
+	return
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/README.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/README.md b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/README.md
new file mode 100644
index 0000000..79ead26
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/README.md
@@ -0,0 +1,27 @@
+# gmx client
+
+`gmxc` is a simple command line client for interacting with gmx enabled processes.
+
+## Usage
+
+### Listing processes
+
+The default invocation of `gmxc` will list the accessible gmx enabled processes currently running
+
+	% ./gmxc 
+	.gmx.16207.0    ["./godoc" "-v" "-http=:8080"]
+
+### Retrieving gmx values
+
+	./gmxc -p 16207 runtime.numcpu
+	runtime.numcpu: 4
+
+	./gmxc -p 14968 'runtime.(numcpu|version)'
+	runtime.version: weekly.2012-01-27 11662
+	runtime.numcpu: 2
+
+### Listing all gmx values
+
+	% ./gmxc -p 16207 keys
+	keys: [keys runtime.memstats runtime.gomaxprocs runtime.version os.args runtime.numcpu runtime.cgocalls]
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/main.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/main.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/main.go
new file mode 100644
index 0000000..071c55e
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/gmxc/main.go
@@ -0,0 +1,129 @@
+package main
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"regexp"
+	"time"
+)
+
+var (
+	delay    = flag.Duration("d", 0, "delay between updates")
+	duration = flag.Duration("D", 0, "duration to output continually")
+
+	pid = flag.Int("p", 0, "process to inspect")
+
+	socketregex = regexp.MustCompile(`\.gmx\.[0-9]+\.0`)
+)
+
+type conn struct {
+	net.Conn
+	*json.Decoder
+	*json.Encoder
+}
+
+func dial(addr string) (*conn, error) {
+	c, err := net.Dial("unix", addr)
+	return &conn{
+		c,
+		json.NewDecoder(c),
+		json.NewEncoder(c),
+	}, err
+}
+
+func listGmxProcesses() {
+	dir, err := os.Open(os.TempDir())
+	if err != nil {
+		log.Fatalf("unable to open %s: %v", os.TempDir(), err)
+	}
+	pids, err := dir.Readdirnames(0)
+	if err != nil {
+		log.Fatalf("unable to read pids: %v", err)
+	}
+	for _, pid := range pids {
+		if socketregex.MatchString(pid) {
+			c, err := dial(filepath.Join(os.TempDir(), pid))
+			if err != nil {
+				continue
+			}
+			defer c.Close()
+			c.Encode([]string{"os.args"})
+			var result = make(map[string]interface{})
+			if err := c.Decode(&result); err != nil {
+				log.Printf("unable to decode response from %s: %v", pid, err)
+				continue
+			}
+			if args, ok := result["os.args"]; ok {
+				fmt.Printf("%s\t%v\n", pid, args)
+			}
+		}
+	}
+}
+
+// fetchKeys returns all the registered keys from the process.
+func fetchKeys(c *conn) []string {
+	// retrieve list of registered keys
+	if err := c.Encode([]string{"keys"}); err != nil {
+		log.Fatalf("unable to send keys request to process: %v", err)
+	}
+	var result = make(map[string][]string)
+	if err := c.Decode(&result); err != nil {
+		log.Fatalf("unable to decode keys response: %v", err)
+	}
+	keys, ok := result["keys"]
+	if !ok {
+		log.Fatalf("gmx server did not return a keys list")
+	}
+	return keys
+}
+
+func main() {
+	flag.Parse()
+	if *pid == 0 {
+		listGmxProcesses()
+		return
+	}
+	c, err := dial(filepath.Join(os.TempDir(), fmt.Sprintf(".gmx.%d.0", *pid)))
+	if err != nil {
+		log.Fatalf("unable to connect to process %d: %v", *pid, err)
+	}
+	defer c.Close()
+
+	// match flag.Args() as regexps
+	registeredKeys := fetchKeys(c)
+	var keys []string
+	for _, a := range flag.Args() {
+		r, err := regexp.Compile(a)
+		if err != nil {
+			log.Fatal("unable to compile regex %v: %v", a, err)
+		}
+		for _, k := range registeredKeys {
+			if r.MatchString(k) {
+				keys = append(keys, k)
+			}
+		}
+	}
+
+	deadline := time.Now().Add(*duration)
+	for {
+		if err := c.Encode(keys); err != nil {
+			log.Fatalf("unable to send request to process: %v", err)
+		}
+		var result = make(map[string]interface{})
+		if err := c.Decode(&result); err != nil {
+			log.Fatalf("unable to decode response: %v", err)
+		}
+		for k, v := range result {
+			fmt.Printf("%s: %v\n", k, v)
+		}
+		if time.Now().After(deadline) {
+			return
+		}
+		time.Sleep(*delay)
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/instrument.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/instrument.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/instrument.go
new file mode 100644
index 0000000..68c4ca5
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/instrument.go
@@ -0,0 +1,41 @@
+package gmx
+
+import (
+	"sync/atomic"
+)
+
+type Counter struct {
+	value uint64
+}
+
+func (c *Counter) Inc() {
+	atomic.AddUint64(&c.value, 1)
+}
+
+func NewCounter(name string) *Counter {
+	c := new(Counter)
+	Publish(name, func() interface{} {
+		return c.value
+	})
+	return c
+}
+
+type Gauge struct {
+	value int64
+}
+
+func (g *Gauge) Inc() {
+	atomic.AddInt64(&g.value, 1)
+}
+
+func (g *Gauge) Dec() {
+	atomic.AddInt64(&g.value, -1)
+}
+
+func NewGauge(name string) *Gauge {
+	g := new(Gauge)
+	Publish(name, func() interface{} {
+		return g.value
+	})
+	return g
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/os.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/os.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/os.go
new file mode 100644
index 0000000..92dd372
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/os.go
@@ -0,0 +1,15 @@
+package gmx
+
+// pkg/os instrumentation
+
+import (
+	"os"
+)
+
+func init() {
+	Publish("os.args", osArgs)
+}
+
+func osArgs() interface{} {
+	return os.Args
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/davecheney/gmx/runtime.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/davecheney/gmx/runtime.go b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/runtime.go
new file mode 100644
index 0000000..ada86fd
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/davecheney/gmx/runtime.go
@@ -0,0 +1,42 @@
+package gmx
+
+// pkg/runtime instrumentation
+
+import "runtime"
+
+var memstats runtime.MemStats
+
+func init() {
+	Publish("runtime.gomaxprocs", runtimeGOMAXPROCS)
+	Publish("runtime.numcgocall", runtimeNumCgoCall)
+	Publish("runtime.numcpu", runtimeNumCPU)
+	Publish("runtime.numgoroutine", runtimeNumGoroutine)
+	Publish("runtime.version", runtimeVersion)
+
+	Publish("runtime.memstats", runtimeMemStats)
+}
+
+func runtimeGOMAXPROCS() interface{} {
+	return runtime.GOMAXPROCS(0)
+}
+
+func runtimeNumCgoCall() interface{} {
+	return runtime.NumCgoCall()
+}
+
+func runtimeNumCPU() interface{} {
+	return runtime.NumCPU()
+}
+
+func runtimeNumGoroutine() interface{} {
+	return runtime.NumGoroutine()
+}
+
+func runtimeVersion() interface{} {
+	return runtime.Version()
+}
+
+func runtimeMemStats() interface{} {
+	runtime.ReadMemStats(&memstats)
+	return memstats
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/LICENSE
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/LICENSE b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/LICENSE
new file mode 100644
index 0000000..efcb241
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/LICENSE
@@ -0,0 +1,10 @@
+Copyright (c) 2014, Eric Urban
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/README.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/README.md b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/README.md
new file mode 100644
index 0000000..bf19193
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/README.md
@@ -0,0 +1,18 @@
+stoppableListener
+=================
+
+An example of a stoppable TCP listener in Go. This library wraps an existing TCP connection object. A goroutine calling `Accept()`
+is interrupted with `StoppedError` whenever the listener is stopped by a call to `Stop()`. Usage is demonstrated below, and in `example/example.go`.
+
+
+```
+	originalListener, err := net.Listen("tcp", ":8080")
+	if err != nil {
+		panic(err)
+	}
+
+	sl, err := stoppableListener.New(originalListener)
+	if err != nil {
+		panic(err)
+	}
+```

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/example/example.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/example/example.go b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/example/example.go
new file mode 100644
index 0000000..3c8b323
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/example/example.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+	"fmt"
+	"github.com/hydrogen18/stoppableListener"
+	"net"
+	"net/http"
+	"os"
+	"os/signal"
+	"sync"
+	"syscall"
+)
+
+func helloHttp(rw http.ResponseWriter, req *http.Request) {
+	rw.WriteHeader(http.StatusOK)
+	fmt.Fprintf(rw, "Hello HTTP!\n")
+}
+
+func main() {
+	originalListener, err := net.Listen("tcp", ":8080")
+	if err != nil {
+		panic(err)
+	}
+
+	sl, err := stoppableListener.New(originalListener)
+	if err != nil {
+		panic(err)
+	}
+
+	http.HandleFunc("/", helloHttp)
+	server := http.Server{}
+
+	stop := make(chan os.Signal)
+	signal.Notify(stop, syscall.SIGINT)
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		server.Serve(sl)
+	}()
+
+	fmt.Printf("Serving HTTP\n")
+	select {
+	case signal := <-stop:
+		fmt.Printf("Got signal:%v\n", signal)
+	}
+	fmt.Printf("Stopping listener\n")
+	sl.Stop()
+	fmt.Printf("Waiting on server\n")
+	wg.Wait()
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/listener.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/listener.go b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/listener.go
new file mode 100644
index 0000000..69a9f33
--- /dev/null
+++ b/traffic_monitor_golang/vendor/github.com/hydrogen18/stoppableListener/listener.go
@@ -0,0 +1,62 @@
+package stoppableListener
+
+import (
+	"errors"
+	"net"
+	"time"
+)
+
+type StoppableListener struct {
+	*net.TCPListener          //Wrapped listener
+	stop             chan int //Channel used only to indicate listener should shutdown
+}
+
+func New(l net.Listener) (*StoppableListener, error) {
+	tcpL, ok := l.(*net.TCPListener)
+
+	if !ok {
+		return nil, errors.New("Cannot wrap listener")
+	}
+
+	retval := &StoppableListener{}
+	retval.TCPListener = tcpL
+	retval.stop = make(chan int)
+
+	return retval, nil
+}
+
+var StoppedError = errors.New("Listener stopped")
+
+func (sl *StoppableListener) Accept() (net.Conn, error) {
+
+	for {
+		//Wait up to one second for a new connection
+		sl.SetDeadline(time.Now().Add(time.Second))
+
+		newConn, err := sl.TCPListener.Accept()
+
+		//Check for the channel being closed
+		select {
+		case <-sl.stop:
+			return nil, StoppedError
+		default:
+			//If the channel is still open, continue as normal
+		}
+
+		if err != nil {
+			netErr, ok := err.(net.Error)
+
+			//If this is a timeout, then continue to wait for
+			//new connections
+			if ok && netErr.Timeout() && netErr.Temporary() {
+				continue
+			}
+		}
+
+		return newConn, err
+	}
+}
+
+func (sl *StoppableListener) Stop() {
+	close(sl.stop)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.gitignore
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.gitignore b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.gitignore
new file mode 100644
index 0000000..4cd0cba
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.gitignore
@@ -0,0 +1,6 @@
+# Setup a Global .gitignore for OS and editor generated files:
+# https://help.github.com/articles/ignoring-files
+# git config --global core.excludesfile ~/.gitignore_global
+
+.vagrant
+*.sublime-project

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.travis.yml
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.travis.yml b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.travis.yml
new file mode 100644
index 0000000..00fd5dd
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/.travis.yml
@@ -0,0 +1,29 @@
+sudo: false
+language: go
+
+go:
+  - 1.5.4
+  - 1.6.1
+  - tip
+
+matrix:
+  allow_failures:
+    - go: tip
+
+before_script:
+  - go get -u github.com/golang/lint/golint
+
+script:
+  - go test -v --race ./...
+
+after_script:
+  - test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
+  - test -z "$(golint ./...     | tee /dev/stderr)"
+  - go vet ./...
+
+os:
+  - linux
+  - osx
+
+notifications:
+  email: false

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/AUTHORS
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/AUTHORS b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/AUTHORS
new file mode 100644
index 0000000..6438bb3
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/AUTHORS
@@ -0,0 +1,43 @@
+# Names should be added to this file as
+#	Name or Organization <email address>
+# The email address is not required for organizations.
+
+# You can update this list using the following command:
+#
+#   $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
+
+# Please keep the list sorted.
+
+Adrien Bustany <ad...@bustany.org>
+Amit Krishnan <am...@oracle.com>
+Bj�rn Erik Pedersen <bj...@gmail.com>
+Caleb Spare <ce...@gmail.com>
+Case Nelson <ca...@teammating.com>
+Chris Howey <ch...@howey.me> <ho...@gmail.com>
+Christoffer Buchholz <ch...@gmail.com>
+Daniel Wagner-Hall <da...@gmail.com>
+Dave Cheney <da...@cheney.net>
+Evan Phoenix <ev...@fallingsnow.net>
+Francisco Souza <f...@souza.cc>
+Hari haran <ha...@gmail.com>
+John C Barstow
+Kelvin Fo <vm...@gmail.com>
+Ken-ichirou MATSUZAWA <ch...@h4.dion.ne.jp>
+Matt Layher <md...@gmail.com>
+Nathan Youngman <gi...@nathany.com>
+Paul Hammond <pa...@paulhammond.org>
+Pawel Knap <pa...@gmail.com>
+Pieter Droogendijk <pi...@binky.org.uk>
+Pursuit92 <Jo...@techpursuit.net>
+Riku Voipio <ri...@linaro.org>
+Rob Figueiredo <ro...@gmail.com>
+Soge Zhang <zh...@gmail.com>
+Tiffany Jernigan <ti...@intel.com>
+Tilak Sharma <ti...@google.com>
+Travis Cline <tr...@gmail.com>
+Tudor Golubenco <tu...@gmail.com>
+Yukang <mo...@gmail.com>
+bronze1man <br...@gmail.com>
+debrando <de...@gmail.com>
+henrikedwards <he...@gmail.com>
+\u94c1\u54e5 <gu...@gmail.com>

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CHANGELOG.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CHANGELOG.md b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CHANGELOG.md
new file mode 100644
index 0000000..675fab9
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CHANGELOG.md
@@ -0,0 +1,291 @@
+# Changelog
+
+## v1.3.0 / 2016-04-19
+
+* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
+
+## v1.2.10 / 2016-03-02
+
+* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
+
+## v1.2.9 / 2016-01-13
+
+kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
+
+## v1.2.8 / 2015-12-17
+
+* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
+* inotify: fix race in test
+* enable race detection for continuous integration (Linux, Mac, Windows)
+
+## v1.2.5 / 2015-10-17
+
+* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
+* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
+* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
+* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
+
+## v1.2.1 / 2015-10-14
+
+* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
+
+## v1.2.0 / 2015-02-08
+
+* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
+* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
+* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
+
+## v1.1.1 / 2015-02-05
+
+* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
+
+## v1.1.0 / 2014-12-12
+
+* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
+    * add low-level functions
+    * only need to store flags on directories
+    * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
+    * done can be an unbuffered channel
+    * remove calls to os.NewSyscallError
+* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
+* kqueue: fix regression in  rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
+
+## v1.0.4 / 2014-09-07
+
+* kqueue: add dragonfly to the build tags.
+* Rename source code files, rearrange code so exported APIs are at the top.
+* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
+
+## v1.0.3 / 2014-08-19
+
+* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
+
+## v1.0.2 / 2014-08-17
+
+* [Fix] Missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
+* [Fix] Make ./path and path equivalent. (thanks @zhsso)
+
+## v1.0.0 / 2014-08-15
+
+* [API] Remove AddWatch on Windows, use Add.
+* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
+* Minor updates based on feedback from golint.
+
+## dev / 2014-07-09
+
+* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
+* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
+
+## dev / 2014-07-04
+
+* kqueue: fix incorrect mutex used in Close()
+* Update example to demonstrate usage of Op.
+
+## dev / 2014-06-28
+
+* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
+* Fix for String() method on Event (thanks Alex Brainman)
+* Don't build on Plan 9 or Solaris (thanks @4ad)
+
+## dev / 2014-06-21
+
+* Events channel of type Event rather than *Event.
+* [internal] use syscall constants directly for inotify and kqueue.
+* [internal] kqueue: rename events to kevents and fileEvent to event.
+
+## dev / 2014-06-19
+
+* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
+* [internal] remove cookie from Event struct (unused).
+* [internal] Event struct has the same definition across every OS.
+* [internal] remove internal watch and removeWatch methods.
+
+## dev / 2014-06-12
+
+* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
+* [API] Pluralized channel names: Events and Errors.
+* [API] Renamed FileEvent struct to Event.
+* [API] Op constants replace methods like IsCreate().
+
+## dev / 2014-06-12
+
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
+
+## dev / 2014-05-23
+
+* [API] Remove current implementation of WatchFlags.
+    * current implementation doesn't take advantage of OS for efficiency
+    * provides little benefit over filtering events as they are received, but has  extra bookkeeping and mutexes
+    * no tests for the current implementation
+    * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
+
+## v0.9.3 / 2014-12-31
+
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
+
+## v0.9.2 / 2014-08-17
+
+* [Backport] Fix missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
+
+## v0.9.1 / 2014-06-12
+
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
+
+## v0.9.0 / 2014-01-17
+
+* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
+* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
+* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
+
+## v0.8.12 / 2013-11-13
+
+* [API] Remove FD_SET and friends from Linux adapter
+
+## v0.8.11 / 2013-11-02
+
+* [Doc] Add Changelog [#72][] (thanks @nathany)
+* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond)
+
+## v0.8.10 / 2013-10-19
+
+* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
+* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
+* [Doc] specify OS-specific limits in README (thanks @debrando)
+
+## v0.8.9 / 2013-09-08
+
+* [Doc] Contributing (thanks @nathany)
+* [Doc] update package path in example code [#63][] (thanks @paulhammond)
+* [Doc] GoCI badge in README (Linux only) [#60][]
+* [Doc] Cross-platform testing with Vagrant  [#59][] (thanks @nathany)
+
+## v0.8.8 / 2013-06-17
+
+* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
+
+## v0.8.7 / 2013-06-03
+
+* [API] Make syscall flags internal
+* [Fix] inotify: ignore event changes
+* [Fix] race in symlink test [#45][] (reported by @srid)
+* [Fix] tests on Windows
+* lower case error messages
+
+## v0.8.6 / 2013-05-23
+
+* kqueue: Use EVT_ONLY flag on Darwin
+* [Doc] Update README with full example
+
+## v0.8.5 / 2013-05-09
+
+* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
+
+## v0.8.4 / 2013-04-07
+
+* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
+
+## v0.8.3 / 2013-03-13
+
+* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
+* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
+
+## v0.8.2 / 2013-02-07
+
+* [Doc] add Authors
+* [Fix] fix data races for map access [#29][] (thanks @fsouza)
+
+## v0.8.1 / 2013-01-09
+
+* [Fix] Windows path separators
+* [Doc] BSD License
+
+## v0.8.0 / 2012-11-09
+
+* kqueue: directory watching improvements (thanks @vmirage)
+* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
+* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
+
+## v0.7.4 / 2012-10-09
+
+* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
+* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
+* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
+* [Fix] kqueue: modify after recreation of file
+
+## v0.7.3 / 2012-09-27
+
+* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
+* [Fix] kqueue: no longer get duplicate CREATE events
+
+## v0.7.2 / 2012-09-01
+
+* kqueue: events for created directories
+
+## v0.7.1 / 2012-07-14
+
+* [Fix] for renaming files
+
+## v0.7.0 / 2012-07-02
+
+* [Feature] FSNotify flags
+* [Fix] inotify: Added file name back to event path
+
+## v0.6.0 / 2012-06-06
+
+* kqueue: watch files after directory created (thanks @tmc)
+
+## v0.5.1 / 2012-05-22
+
+* [Fix] inotify: remove all watches before Close()
+
+## v0.5.0 / 2012-05-03
+
+* [API] kqueue: return errors during watch instead of sending over channel
+* kqueue: match symlink behavior on Linux
+* inotify: add `DELETE_SELF` (requested by @taralx)
+* [Fix] kqueue: handle EINTR (reported by @robfig)
+* [Doc] Godoc example [#1][] (thanks @davecheney)
+
+## v0.4.0 / 2012-03-30
+
+* Go 1 released: build with go tool
+* [Feature] Windows support using winfsnotify
+* Windows does not have attribute change notifications
+* Roll attribute notifications into IsModify
+
+## v0.3.0 / 2012-02-19
+
+* kqueue: add files when watch directory
+
+## v0.2.0 / 2011-12-30
+
+* update to latest Go weekly code
+
+## v0.1.0 / 2011-10-19
+
+* kqueue: add watch on file creation to match inotify
+* kqueue: create file event
+* inotify: ignore `IN_IGNORED` events
+* event String()
+* linux: common FileEvent functions
+* initial commit
+
+[#79]: https://github.com/howeyc/fsnotify/pull/79
+[#77]: https://github.com/howeyc/fsnotify/pull/77
+[#72]: https://github.com/howeyc/fsnotify/issues/72
+[#71]: https://github.com/howeyc/fsnotify/issues/71
+[#70]: https://github.com/howeyc/fsnotify/issues/70
+[#63]: https://github.com/howeyc/fsnotify/issues/63
+[#62]: https://github.com/howeyc/fsnotify/issues/62
+[#60]: https://github.com/howeyc/fsnotify/issues/60
+[#59]: https://github.com/howeyc/fsnotify/issues/59
+[#49]: https://github.com/howeyc/fsnotify/issues/49
+[#45]: https://github.com/howeyc/fsnotify/issues/45
+[#40]: https://github.com/howeyc/fsnotify/issues/40
+[#36]: https://github.com/howeyc/fsnotify/issues/36
+[#33]: https://github.com/howeyc/fsnotify/issues/33
+[#29]: https://github.com/howeyc/fsnotify/issues/29
+[#25]: https://github.com/howeyc/fsnotify/issues/25
+[#24]: https://github.com/howeyc/fsnotify/issues/24
+[#21]: https://github.com/howeyc/fsnotify/issues/21

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CONTRIBUTING.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CONTRIBUTING.md b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CONTRIBUTING.md
new file mode 100644
index 0000000..617e45a
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+# Contributing
+
+## Issues
+
+* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
+* Please indicate the platform you are using fsnotify on.
+* A code example to reproduce the problem is appreciated.
+
+## Pull Requests
+
+### Contributor License Agreement
+
+fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
+
+Please indicate that you have signed the CLA in your pull request.
+
+### How fsnotify is Developed
+
+* Development is done on feature branches.
+* Tests are run on BSD, Linux, OS X and Windows.
+* Pull requests are reviewed and [applied to master][am] using [hub][].
+  * Maintainers may modify or squash commits rather than asking contributors to.
+* To issue a new release, the maintainers will:
+  * Update the CHANGELOG
+  * Tag a version, which will become available through gopkg.in.
+ 
+### How to Fork
+
+For smooth sailing, always use the original import path. Installing with `go get` makes this easy. 
+
+1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Ensure everything works and the tests pass (see below)
+4. Commit your changes (`git commit -am 'Add some feature'`)
+
+Contribute upstream:
+
+1. Fork fsnotify on GitHub
+2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
+3. Push to the branch (`git push fork my-new-feature`)
+4. Create a new Pull Request on GitHub
+
+This workflow is [thoroughly explained by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/).
+
+### Testing
+
+fsnotify uses build tags to compile different code on Linux, BSD, OS X, and Windows.
+
+Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
+
+To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
+
+* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
+* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
+* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
+* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
+* When you're done, you will want to halt or destroy the Vagrant boxes.
+
+Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
+
+Right now there is no equivalent solution for Windows and OS X, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
+
+### Maintainers
+
+Help maintaining fsnotify is welcome. To be a maintainer:
+
+* Submit a pull request and sign the CLA as above.
+* You must be able to run the test suite on Mac, Windows, Linux and BSD.
+
+To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
+
+All code changes should be internal pull requests.
+
+Releases are tagged using [Semantic Versioning](http://semver.org/).
+
+[hub]: https://github.com/github/hub
+[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/LICENSE
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/LICENSE b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/LICENSE
new file mode 100644
index 0000000..f21e540
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+Copyright (c) 2012 fsnotify Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/README.md
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/README.md b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/README.md
new file mode 100644
index 0000000..5ebce86
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/README.md
@@ -0,0 +1,50 @@
+# File system notifications for Go
+
+[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Coverage](http://gocover.io/_badge/github.com/fsnotify/fsnotify)](http://gocover.io/github.com/fsnotify/fsnotify) 
+
+fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
+
+```console
+go get -u golang.org/x/sys/...
+```
+
+Cross platform: Windows, Linux, BSD and OS X.
+
+|Adapter   |OS        |Status    |
+|----------|----------|----------|
+|inotify   |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
+|kqueue    |BSD, OS X, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
+|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
+|FSEvents  |OS X          |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
+|FEN       |Solaris 11    |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
+|fanotify  |Linux 2.6.37+ | |
+|USN Journals |Windows    |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
+|Polling   |*All*         |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
+
+\* Android and iOS are untested.
+
+Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) for usage. Consult the [Wiki](https://github.com/fsnotify/fsnotify/wiki) for the FAQ and further information.
+
+## API stability
+
+fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). 
+
+All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
+
+Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
+
+## Contributing
+
+Please refer to [CONTRIBUTING][] before opening an issue or pull request.
+
+## Example
+
+See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
+
+[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
+
+## Related Projects
+
+* [notify](https://github.com/rjeczalik/notify)
+* [fsevents](https://github.com/fsnotify/fsevents)
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/example_test.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/example_test.go b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/example_test.go
new file mode 100644
index 0000000..700502c
--- /dev/null
+++ b/traffic_monitor_golang/vendor/gopkg.in/fsnotify.v1/example_test.go
@@ -0,0 +1,42 @@
+// 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_test
+
+import (
+	"log"
+
+	"github.com/fsnotify/fsnotify"
+)
+
+func ExampleNewWatcher() {
+	watcher, err := fsnotify.NewWatcher()
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer watcher.Close()
+
+	done := make(chan bool)
+	go func() {
+		for {
+			select {
+			case event := <-watcher.Events:
+				log.Println("event:", event)
+				if event.Op&fsnotify.Write == fsnotify.Write {
+					log.Println("modified file:", event.Name)
+				}
+			case err := <-watcher.Errors:
+				log.Println("error:", err)
+			}
+		}
+	}()
+
+	err = watcher.Add("/tmp/foo")
+	if err != nil {
+		log.Fatal(err)
+	}
+	<-done
+}