http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/manager/peer.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/peer.go 
b/traffic_monitor/experimental/traffic_monitor/manager/peer.go
deleted file mode 100644
index 3b4a209..0000000
--- a/traffic_monitor/experimental/traffic_monitor/manager/peer.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package manager
-
-/*
- * 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"
-       "sort"
-       "strings"
-       "time"
-
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/util"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/config"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/health"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
-       todata 
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
-)
-
-// StartPeerManager listens for peer results, and when it gets one, it adds it 
to the peerStates list, and optimistically combines the good results into 
combinedStates
-func StartPeerManager(
-       peerChan <-chan peer.Result,
-       localStates peer.CRStatesThreadsafe,
-       peerStates peer.CRStatesPeersThreadsafe,
-       events health.ThreadsafeEvents,
-       peerOptimistic bool,
-       toData todata.TODataThreadsafe,
-       cfg config.Config,
-) (peer.CRStatesThreadsafe, health.ThreadsafeEvents) {
-       combinedStates := peer.NewCRStatesThreadsafe()
-       overrideMap := map[enum.CacheName]bool{}
-
-       go func() {
-               for peerResult := range peerChan {
-                       comparePeerState(events, peerResult, peerStates)
-                       peerStates.Set(peerResult)
-                       combineCrStates(events, peerOptimistic, peerStates, 
localStates.Get(), combinedStates, overrideMap, toData)
-                       peerResult.PollFinished <- peerResult.PollID
-               }
-       }()
-       return combinedStates, events
-}
-
-func comparePeerState(events health.ThreadsafeEvents, result peer.Result, 
peerStates peer.CRStatesPeersThreadsafe) {
-       if result.Available != peerStates.GetPeerAvailability(result.ID) {
-               events.Add(health.Event{Time: result.Time, Unix: 
result.Time.Unix(), Description: util.JoinErrorsString(result.Errors), Name: 
result.ID.String(), Hostname: result.ID.String(), Type: "Peer", Available: 
result.Available})
-       }
-}
-
-// TODO JvD: add deliveryservice stuff
-func combineCrStates(events health.ThreadsafeEvents, peerOptimistic bool, 
peerStates peer.CRStatesPeersThreadsafe, localStates peer.Crstates, 
combinedStates peer.CRStatesThreadsafe, overrideMap map[enum.CacheName]bool, 
toData todata.TODataThreadsafe) {
-       toDataCopy := toData.Get()
-
-       for cacheName, localCacheState := range localStates.Caches { // 
localStates gets pruned when servers are disabled, it's the source of truth
-               var overrideCondition string
-               available := false
-               override := overrideMap[cacheName]
-
-               if localCacheState.IsAvailable {
-                       available = true // we don't care about the peers, we 
got a "good one", and we're optimistic
-
-                       if override {
-                               overrideCondition = "cleared; healthy locally"
-                               overrideMap[cacheName] = false
-                       }
-               } else if peerOptimistic {
-                       if !peerStates.HasAvailablePeers() {
-                               if override {
-                                       overrideCondition = "irrelevant; no 
peers online"
-                                       overrideMap[cacheName] = false
-                               }
-                       } else {
-                               onlineOnPeers := make([]string, 0)
-
-                               for peer, peerCrStates := range 
peerStates.GetCrstates() {
-                                       if peerStates.GetPeerAvailability(peer) 
{
-                                               if 
peerCrStates.Caches[cacheName].IsAvailable {
-                                                       onlineOnPeers = 
append(onlineOnPeers, peer.String())
-                                               }
-                                       }
-                               }
-
-                               if len(onlineOnPeers) > 0 {
-                                       available = true
-
-                                       if !override {
-                                               overrideCondition = 
fmt.Sprintf("detected; healthy on (at least) %s", strings.Join(onlineOnPeers, 
", "))
-                                               overrideMap[cacheName] = true
-                                       }
-                               } else {
-                                       if override {
-                                               overrideCondition = 
"irrelevant; not online on any peers"
-                                               overrideMap[cacheName] = false
-                                       }
-                               }
-                       }
-               }
-
-               if overrideCondition != "" {
-                       events.Add(health.Event{Time: time.Now(), Unix: 
time.Now().Unix(), Description: fmt.Sprintf("Health protocol override condition 
%s", overrideCondition), Name: cacheName.String(), Hostname: 
cacheName.String(), Type: toDataCopy.ServerTypes[cacheName].String(), 
Available: available})
-               }
-
-               combinedStates.SetCache(cacheName, 
peer.IsAvailable{IsAvailable: available})
-       }
-
-       for deliveryServiceName, localDeliveryService := range 
localStates.Deliveryservice {
-               deliveryService := peer.Deliveryservice{IsAvailable: false, 
DisabledLocations: []enum.CacheName{}} // important to initialize 
DisabledLocations, so JSON is `[]` not `null`
-               if localDeliveryService.IsAvailable {
-                       deliveryService.IsAvailable = true
-               }
-               deliveryService.DisabledLocations = 
localDeliveryService.DisabledLocations
-
-               for peerName, iPeerStates := range peerStates.GetCrstates() {
-                       peerDeliveryService, ok := 
iPeerStates.Deliveryservice[deliveryServiceName]
-                       if !ok {
-                               log.Warnf("local delivery service %s not found 
in peer %s\n", deliveryServiceName, peerName)
-                               continue
-                       }
-                       if peerDeliveryService.IsAvailable {
-                               deliveryService.IsAvailable = true
-                       }
-                       deliveryService.DisabledLocations = 
intersection(deliveryService.DisabledLocations, 
peerDeliveryService.DisabledLocations)
-               }
-               combinedStates.SetDeliveryService(deliveryServiceName, 
deliveryService)
-       }
-}
-
-// CacheNameSlice is a slice of cache names, which fulfills the 
`sort.Interface` interface.
-type CacheNameSlice []enum.CacheName
-
-func (p CacheNameSlice) Len() int           { return len(p) }
-func (p CacheNameSlice) Less(i, j int) bool { return p[i] < p[j] }
-func (p CacheNameSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
-
-// intersection returns strings in both a and b.
-// Note this modifies a and b. Specifically, it sorts them. If that isn't 
acceptable, pass copies of your real data.
-func intersection(a []enum.CacheName, b []enum.CacheName) []enum.CacheName {
-       sort.Sort(CacheNameSlice(a))
-       sort.Sort(CacheNameSlice(b))
-       c := []enum.CacheName{} // important to initialize, so JSON is `[]` not 
`null`
-       for _, s := range a {
-               i := sort.Search(len(b), func(i int) bool { return b[i] >= s })
-               if i < len(b) && b[i] == s {
-                       c = append(c, s)
-               }
-       }
-       return c
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/manager/stat.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/stat.go 
b/traffic_monitor/experimental/traffic_monitor/manager/stat.go
deleted file mode 100644
index 50ce052..0000000
--- a/traffic_monitor/experimental/traffic_monitor/manager/stat.go
+++ /dev/null
@@ -1,219 +0,0 @@
-package manager
-
-/*
- * 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 (
-       "time"
-
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/config"
-       ds 
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservice"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/health"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/threadsafe"
-       todata 
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
-       to "github.com/apache/incubator-trafficcontrol/traffic_ops/client"
-)
-
-func pruneHistory(history []cache.Result, limit uint64) []cache.Result {
-       if uint64(len(history)) > limit {
-               history = history[:limit-1]
-       }
-       return history
-}
-
-func getNewCaches(localStates peer.CRStatesThreadsafe, monitorConfigTS 
TrafficMonitorConfigMapThreadsafe) map[enum.CacheName]struct{} {
-       monitorConfig := monitorConfigTS.Get()
-       caches := map[enum.CacheName]struct{}{}
-       for cacheName := range localStates.GetCaches() {
-               // ONLINE and OFFLINE caches are not polled.
-               // TODO add a function IsPolled() which can be called by this 
and the monitorConfig func which sets the polling, to prevent updating in one 
place breaking the other.
-               if ts, ok := monitorConfig.TrafficServer[string(cacheName)]; 
!ok || ts.Status == "ONLINE" || ts.Status == "OFFLINE" {
-                       continue
-               }
-               caches[cacheName] = struct{}{}
-       }
-       return caches
-}
-
-// StartStatHistoryManager fetches the full statistics data from ATS Astats. 
This includes everything needed for all calculations, such as Delivery 
Services. This is expensive, though, and may be hard on ATS, so it should poll 
less often.
-// For a fast 'is it alive' poll, use the Health Result Manager poll.
-// Returns the stat history, the duration between the stat poll for each 
cache, the last Kbps data, the calculated Delivery Service stats, and the 
unpolled caches list.
-func StartStatHistoryManager(
-       cacheStatChan <-chan cache.Result,
-       localStates peer.CRStatesThreadsafe,
-       combinedStates peer.CRStatesThreadsafe,
-       toData todata.TODataThreadsafe,
-       cachesChanged <-chan struct{},
-       errorCount threadsafe.Uint,
-       cfg config.Config,
-       monitorConfig TrafficMonitorConfigMapThreadsafe,
-       events health.ThreadsafeEvents,
-) (threadsafe.ResultInfoHistory, threadsafe.ResultStatHistory, 
threadsafe.CacheKbpses, DurationMapThreadsafe, threadsafe.LastStats, 
threadsafe.DSStatsReader, threadsafe.UnpolledCaches, 
threadsafe.CacheAvailableStatus) {
-       statInfoHistory := threadsafe.NewResultInfoHistory()
-       statResultHistory := threadsafe.NewResultStatHistory()
-       statMaxKbpses := threadsafe.NewCacheKbpses()
-       lastStatDurations := NewDurationMapThreadsafe()
-       lastStatEndTimes := map[enum.CacheName]time.Time{}
-       lastStats := threadsafe.NewLastStats()
-       dsStats := threadsafe.NewDSStats()
-       unpolledCaches := threadsafe.NewUnpolledCaches()
-       tickInterval := cfg.StatFlushInterval
-       localCacheStatus := threadsafe.NewCacheAvailableStatus()
-
-       precomputedData := map[enum.CacheName]cache.PrecomputedData{}
-       lastResults := map[enum.CacheName]cache.Result{}
-
-       process := func(results []cache.Result) {
-               processStatResults(results, statInfoHistory, statResultHistory, 
statMaxKbpses, combinedStates.Get(), lastStats, toData.Get(), errorCount, 
dsStats, lastStatEndTimes, lastStatDurations, unpolledCaches, 
monitorConfig.Get(), precomputedData, lastResults, localStates, events, 
localCacheStatus)
-       }
-
-       go func() {
-               var ticker *time.Ticker
-               <-cachesChanged // wait for the signal that localStates have 
been set
-               unpolledCaches.SetNewCaches(getNewCaches(localStates, 
monitorConfig))
-
-               for {
-                       var results []cache.Result
-                       results = append(results, <-cacheStatChan)
-                       if ticker != nil {
-                               ticker.Stop()
-                       }
-                       ticker = time.NewTicker(tickInterval)
-               innerLoop:
-                       for {
-                               select {
-                               case <-cachesChanged:
-                                       
unpolledCaches.SetNewCaches(getNewCaches(localStates, monitorConfig))
-                               case <-ticker.C:
-                                       log.Infof("StatHistoryManager flushing 
queued results\n")
-                                       process(results)
-                                       break innerLoop
-                               default:
-                                       select {
-                                       case r := <-cacheStatChan:
-                                               results = append(results, r)
-                                       default:
-                                               process(results)
-                                               break innerLoop
-                                       }
-                               }
-                       }
-               }
-       }()
-       return statInfoHistory, statResultHistory, statMaxKbpses, 
lastStatDurations, lastStats, &dsStats, unpolledCaches, localCacheStatus
-}
-
-// processStatResults processes the given results, creating and setting 
DSStats, LastStats, and other stats. Note this is NOT threadsafe, and MUST NOT 
be called from multiple threads.
-func processStatResults(
-       results []cache.Result,
-       statInfoHistoryThreadsafe threadsafe.ResultInfoHistory,
-       statResultHistoryThreadsafe threadsafe.ResultStatHistory,
-       statMaxKbpsesThreadsafe threadsafe.CacheKbpses,
-       combinedStates peer.Crstates,
-       lastStats threadsafe.LastStats,
-       toData todata.TOData,
-       errorCount threadsafe.Uint,
-       dsStats threadsafe.DSStats,
-       lastStatEndTimes map[enum.CacheName]time.Time,
-       lastStatDurationsThreadsafe DurationMapThreadsafe,
-       unpolledCaches threadsafe.UnpolledCaches,
-       mc to.TrafficMonitorConfigMap,
-       precomputedData map[enum.CacheName]cache.PrecomputedData,
-       lastResults map[enum.CacheName]cache.Result,
-       localStates peer.CRStatesThreadsafe,
-       events health.ThreadsafeEvents,
-       localCacheStatusThreadsafe threadsafe.CacheAvailableStatus,
-) {
-       if len(results) == 0 {
-               return
-       }
-       defer func() {
-               for _, r := range results {
-                       // log.Debugf("poll %v %v statfinish\n", result.PollID, 
endTime)
-                       r.PollFinished <- r.PollID
-               }
-       }()
-
-       // setting the statHistory could be put in a goroutine concurrent with 
`ds.CreateStats`, if it were slow
-       statInfoHistory := statInfoHistoryThreadsafe.Get().Copy()
-       statResultHistory := statResultHistoryThreadsafe.Get().Copy()
-       statMaxKbpses := statMaxKbpsesThreadsafe.Get().Copy()
-
-       for i, result := range results {
-               maxStats := 
uint64(mc.Profile[mc.TrafficServer[string(result.ID)].Profile].Parameters.HistoryCount)
-               if maxStats < 1 {
-                       log.Infof("processStatResults got history count %v for 
%v, setting to 1\n", maxStats, result.ID)
-                       maxStats = 1
-               }
-
-               // TODO determine if we want to add results with errors, or 
just print the errors now and don't add them.
-               if lastResult, ok := lastResults[result.ID]; ok && result.Error 
== nil {
-                       health.GetVitals(&result, &lastResult, &mc) // TODO 
precompute
-                       if result.Error == nil {
-                               results[i] = result
-                       } else {
-                               log.Errorf("stat poll getting vitals for %v: 
%v\n", result.ID, result.Error)
-                       }
-               }
-               statInfoHistory.Add(result, maxStats)
-               statResultHistory.Add(result, maxStats)
-               // Don't add errored maxes or precomputed DSStats
-               if result.Error == nil {
-                       // max and precomputed always contain the latest result 
from each cache
-                       statMaxKbpses.AddMax(result)
-                       // if we failed to compute the OutBytes, keep the 
outbytes of the last result.
-                       if result.PrecomputedData.OutBytes == 0 {
-                               result.PrecomputedData.OutBytes = 
precomputedData[result.ID].OutBytes
-                       }
-                       precomputedData[result.ID] = result.PrecomputedData
-
-               }
-               lastResults[result.ID] = result
-       }
-       statInfoHistoryThreadsafe.Set(statInfoHistory)
-       statResultHistoryThreadsafe.Set(statResultHistory)
-       statMaxKbpsesThreadsafe.Set(statMaxKbpses)
-
-       newDsStats, newLastStats, err := ds.CreateStats(precomputedData, 
toData, combinedStates, lastStats.Get().Copy(), time.Now(), mc, events)
-       if err != nil {
-               errorCount.Inc()
-               log.Errorf("getting deliveryservice: %v\n", err)
-       } else {
-               dsStats.Set(newDsStats)
-               lastStats.Set(newLastStats)
-       }
-
-       health.CalcAvailability(results, "stat", statResultHistory, mc, toData, 
localCacheStatusThreadsafe, localStates, events)
-
-       endTime := time.Now()
-       lastStatDurations := lastStatDurationsThreadsafe.Get().Copy()
-       for _, result := range results {
-               if lastStatStart, ok := lastStatEndTimes[result.ID]; ok {
-                       d := time.Since(lastStatStart)
-                       lastStatDurations[result.ID] = d
-               }
-               lastStatEndTimes[result.ID] = endTime
-       }
-       lastStatDurationsThreadsafe.Set(lastStatDurations)
-       unpolledCaches.SetPolled(results, lastStats.Get())
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/crstates.go 
b/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
deleted file mode 100644
index cac90e1..0000000
--- a/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
+++ /dev/null
@@ -1,233 +0,0 @@
-package peer
-
-/*
- * 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"
-       "sync"
-
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-)
-
-// Crstates includes availability data for caches and delivery services, as 
gathered and aggregated by this Traffic Monitor. It is designed to be served at 
an API endpoint primarily for Traffic Routers (Content Router) to consume.
-// TODO rename to `CRStates`
-type Crstates struct {
-       Caches          map[enum.CacheName]IsAvailable               
`json:"caches"`
-       Deliveryservice map[enum.DeliveryServiceName]Deliveryservice 
`json:"deliveryServices"`
-}
-
-// NewCrstates creates a new CR states object, initializing pointer members.
-func NewCrstates() Crstates {
-       return Crstates{
-               Caches:          map[enum.CacheName]IsAvailable{},
-               Deliveryservice: map[enum.DeliveryServiceName]Deliveryservice{},
-       }
-}
-
-// Copy creates a deep copy of this object. It does not mutate, and is thus 
safe for multiple goroutines.
-func (a Crstates) Copy() Crstates {
-       b := NewCrstates()
-       for k, v := range a.Caches {
-               b.Caches[k] = v
-       }
-       for k, v := range a.Deliveryservice {
-               b.Deliveryservice[k] = v
-       }
-       return b
-}
-
-// CopyDeliveryservices creates a deep copy of the delivery service 
availability data.. It does not mutate, and is thus safe for multiple 
goroutines.
-func (a Crstates) CopyDeliveryservices() 
map[enum.DeliveryServiceName]Deliveryservice {
-       b := map[enum.DeliveryServiceName]Deliveryservice{}
-       for k, v := range a.Deliveryservice {
-               b[k] = v
-       }
-       return b
-}
-
-// CopyCaches creates a deep copy of the cache availability data.. It does not 
mutate, and is thus safe for multiple goroutines.
-func (a Crstates) CopyCaches() map[enum.CacheName]IsAvailable {
-       b := map[enum.CacheName]IsAvailable{}
-       for k, v := range a.Caches {
-               b[k] = v
-       }
-       return b
-}
-
-// IsAvailable contains whether the given cache or delivery service is 
available. It is designed for JSON serialization, namely in the Traffic Monitor 
1.0 API.
-type IsAvailable struct {
-       IsAvailable bool `json:"isAvailable"`
-}
-
-// Deliveryservice contains data about the availability of a particular 
delivery service, and which caches in that delivery service have been marked as 
unavailable.
-type Deliveryservice struct {
-       DisabledLocations []enum.CacheName `json:"disabledLocations"`
-       IsAvailable       bool             `json:"isAvailable"`
-}
-
-// CrstatesUnMarshall takes bytes of a JSON string, and unmarshals them into a 
Crstates object.
-func CrstatesUnMarshall(body []byte) (Crstates, error) {
-       var crStates Crstates
-       err := json.Unmarshal(body, &crStates)
-       return crStates, err
-}
-
-// CrstatesMarshall serializes the given Crstates into bytes.
-func CrstatesMarshall(states Crstates) ([]byte, error) {
-       return json.Marshal(states)
-}
-
-// CRStatesThreadsafe provides safe access for multiple goroutines to read a 
single Crstates object, with a single goroutine writer.
-// This could be made lock-free, if the performance was necessary
-// TODO add separate locks for Caches and Deliveryservice maps?
-type CRStatesThreadsafe struct {
-       crStates *Crstates
-       m        *sync.RWMutex
-}
-
-// NewCRStatesThreadsafe creates a new CRStatesThreadsafe object safe for 
multiple goroutine readers and a single writer.
-func NewCRStatesThreadsafe() CRStatesThreadsafe {
-       crs := NewCrstates()
-       return CRStatesThreadsafe{m: &sync.RWMutex{}, crStates: &crs}
-}
-
-// Get returns the internal Crstates object for reading.
-func (t *CRStatesThreadsafe) Get() Crstates {
-       t.m.RLock()
-       defer t.m.RUnlock()
-       return t.crStates.Copy()
-}
-
-// GetDeliveryServices returns the internal Crstates delivery services map for 
reading.
-// TODO add GetCaches, GetDeliveryservices?
-func (t *CRStatesThreadsafe) GetDeliveryServices() 
map[enum.DeliveryServiceName]Deliveryservice {
-       t.m.RLock()
-       defer t.m.RUnlock()
-       return t.crStates.CopyDeliveryservices()
-}
-
-// GetCache returns the availability data of the given cache. This does not 
mutate, and is thus safe for multiple goroutines to call.
-func (t *CRStatesThreadsafe) GetCache(name enum.CacheName) (available 
IsAvailable, ok bool) {
-       t.m.RLock()
-       available, ok = t.crStates.Caches[name]
-       t.m.RUnlock()
-       return
-}
-
-// GetCaches returns the availability data of all caches. This does not 
mutate, and is thus safe for multiple goroutines to call.
-func (t *CRStatesThreadsafe) GetCaches() map[enum.CacheName]IsAvailable {
-       t.m.RLock()
-       defer t.m.RUnlock()
-       return t.crStates.CopyCaches()
-}
-
-// GetDeliveryService returns the availability data of the given delivery 
service. This does not mutate, and is thus safe for multiple goroutines to call.
-func (t *CRStatesThreadsafe) GetDeliveryService(name enum.DeliveryServiceName) 
(ds Deliveryservice, ok bool) {
-       t.m.RLock()
-       ds, ok = t.crStates.Deliveryservice[name]
-       t.m.RUnlock()
-       return
-}
-
-// SetCache sets the internal availability data for a particular cache.
-func (t *CRStatesThreadsafe) SetCache(cacheName enum.CacheName, available 
IsAvailable) {
-       t.m.Lock()
-       t.crStates.Caches[cacheName] = available
-       t.m.Unlock()
-}
-
-// DeleteCache deletes the given cache from the internal data.
-func (t *CRStatesThreadsafe) DeleteCache(name enum.CacheName) {
-       t.m.Lock()
-       delete(t.crStates.Caches, name)
-       t.m.Unlock()
-}
-
-// SetDeliveryService sets the availability data for the given delivery 
service.
-func (t *CRStatesThreadsafe) SetDeliveryService(name enum.DeliveryServiceName, 
ds Deliveryservice) {
-       t.m.Lock()
-       t.crStates.Deliveryservice[name] = ds
-       t.m.Unlock()
-}
-
-// DeleteDeliveryService deletes the given delivery service from the internal 
data. This MUST NOT be called by multiple goroutines.
-func (t *CRStatesThreadsafe) DeleteDeliveryService(name 
enum.DeliveryServiceName) {
-       t.m.Lock()
-       delete(t.crStates.Deliveryservice, name)
-       t.m.Unlock()
-}
-
-// CRStatesPeersThreadsafe provides safe access for multiple goroutines to 
read a map of Traffic Monitor peers to their returned Crstates, with a single 
goroutine writer.
-// This could be made lock-free, if the performance was necessary
-type CRStatesPeersThreadsafe struct {
-       crStates   map[enum.TrafficMonitorName]Crstates
-       peerStates map[enum.TrafficMonitorName]bool
-       m          *sync.RWMutex
-}
-
-// NewCRStatesPeersThreadsafe creates a new CRStatesPeers object safe for 
multiple goroutine readers and a single writer.
-func NewCRStatesPeersThreadsafe() CRStatesPeersThreadsafe {
-       return CRStatesPeersThreadsafe{m: &sync.RWMutex{}, crStates: 
map[enum.TrafficMonitorName]Crstates{}, peerStates: 
map[enum.TrafficMonitorName]bool{}}
-}
-
-// GetCrstates returns the internal Traffic Monitor peer Crstates data. This 
MUST NOT be modified.
-func (t *CRStatesPeersThreadsafe) GetCrstates() 
map[enum.TrafficMonitorName]Crstates {
-       t.m.RLock()
-       m := map[enum.TrafficMonitorName]Crstates{}
-       for k, v := range t.crStates {
-               m[k] = v.Copy()
-       }
-       t.m.RUnlock()
-       return m
-}
-
-// GetPeerAvailability returns the state of the given peer
-func (t *CRStatesPeersThreadsafe) GetPeerAvailability(peer 
enum.TrafficMonitorName) bool {
-       t.m.RLock()
-       availability := t.peerStates[peer]
-       t.m.RUnlock()
-       return availability
-}
-
-// HasAvailablePeers returns true if at least one peer is online
-func (t *CRStatesPeersThreadsafe) HasAvailablePeers() bool {
-       availablePeers := false
-
-       t.m.RLock()
-
-       for _, available := range t.peerStates {
-               if available {
-                       availablePeers = true
-                       break
-               }
-       }
-
-       t.m.RUnlock()
-
-       return availablePeers
-}
-
-// Set sets the internal Traffic Monitor peer state and Crstates data. This 
MUST NOT be called by multiple goroutines.
-func (t *CRStatesPeersThreadsafe) Set(result Result) {
-       t.m.Lock()
-       t.crStates[result.ID] = result.PeerStates
-       t.peerStates[result.ID] = result.Available
-       t.m.Unlock()
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/peer/crstates.json
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/crstates.json 
b/traffic_monitor/experimental/traffic_monitor/peer/crstates.json
deleted file mode 100644
index d8ffe03..0000000
--- a/traffic_monitor/experimental/traffic_monitor/peer/crstates.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "caches": {
-    "ats-edge-cache-0": {"isAvailable": true},
-    "ats-edge-cache-1": {"isAvailable": false}
-  },
-  "deliveryServices": {
-    "delivery-service-0": {
-      "disabledLocations": [],
-      "isAvailable": true
-    },
-    "delivery-service-1": {
-      "disabledLocations": [],
-      "isAvailable": true
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/peer/peer.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/peer.go 
b/traffic_monitor/experimental/traffic_monitor/peer/peer.go
deleted file mode 100644
index 66755f8..0000000
--- a/traffic_monitor/experimental/traffic_monitor/peer/peer.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package peer
-
-/*
- * 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"
-       "io"
-       "time"
-
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-)
-
-// Handler handles peer Traffic Monitor data, taking a raw reader, parsing the 
data, and passing a result object to the ResultChannel. This fulfills the 
common `Handler` interface.
-type Handler struct {
-       ResultChannel chan Result
-       Notify        int
-}
-
-// NewHandler returns a new peer Handler.
-func NewHandler() Handler {
-       return Handler{ResultChannel: make(chan Result)}
-}
-
-// Result contains the data parsed from polling a peer Traffic Monitor.
-type Result struct {
-       ID           enum.TrafficMonitorName
-       Available    bool
-       Errors       []error
-       PeerStates   Crstates
-       PollID       uint64
-       PollFinished chan<- uint64
-       Time         time.Time
-}
-
-// Handle handles a response from a polled Traffic Monitor peer, parsing the 
data and forwarding it to the ResultChannel.
-func (handler Handler) Handle(id string, r io.Reader, reqTime time.Duration, 
err error, pollID uint64, pollFinished chan<- uint64) {
-       result := Result{
-               ID:           enum.TrafficMonitorName(id),
-               Available:    false,
-               Errors:       []error{},
-               PollID:       pollID,
-               PollFinished: pollFinished,
-               Time:         time.Now(),
-       }
-
-       if err != nil {
-               result.Errors = append(result.Errors, err)
-       }
-
-       if r != nil {
-               dec := json.NewDecoder(r)
-               err = dec.Decode(&result.PeerStates)
-
-               if err == nil {
-                       result.Available = true
-               } else {
-                       result.Errors = append(result.Errors, err)
-               }
-       }
-
-       handler.ResultChannel <- result
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/peer/peer_test.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/peer_test.go 
b/traffic_monitor/experimental/traffic_monitor/peer/peer_test.go
deleted file mode 100644
index 627a825..0000000
--- a/traffic_monitor/experimental/traffic_monitor/peer/peer_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package peer
-
-/*
- * 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"
-       "io/ioutil"
-       "testing"
-)
-
-func TestCrStates(t *testing.T) {
-       t.Log("Running Peer Tests")
-
-       text, err := ioutil.ReadFile("crstates.json")
-       if err != nil {
-               t.Log(err)
-       }
-       crStates, err := CrstatesUnMarshall(text)
-       if err != nil {
-               t.Log(err)
-       }
-       fmt.Println(len(crStates.Caches), "caches found")
-       for cacheName, crState := range crStates.Caches {
-               t.Logf("%v -> %v", cacheName, crState.IsAvailable)
-       }
-
-       fmt.Println(len(crStates.Deliveryservice), "deliveryservices found")
-       for dsName, deliveryService := range crStates.Deliveryservice {
-               t.Logf("%v -> %v (len:%v)", dsName, 
deliveryService.IsAvailable, len(deliveryService.DisabledLocations))
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/srvhttp/srvhttp.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/srvhttp/srvhttp.go 
b/traffic_monitor/experimental/traffic_monitor/srvhttp/srvhttp.go
deleted file mode 100644
index c7c1362..0000000
--- a/traffic_monitor/experimental/traffic_monitor/srvhttp/srvhttp.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package srvhttp
-
-/*
- * 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"
-       "io/ioutil"
-       "net"
-       "net/http"
-       "net/url"
-       "sync"
-       "time"
-
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
-       "github.com/hydrogen18/stoppableListener"
-)
-
-// GetCommonAPIData calculates and returns API data common to most endpoints
-func GetCommonAPIData(params url.Values, t time.Time) CommonAPIData {
-       return CommonAPIData{
-               QueryParams: ParametersStr(params),
-               DateStr:     DateStr(t),
-       }
-}
-
-// CommonAPIData contains generic data common to most endpoints.
-type CommonAPIData struct {
-       QueryParams string `json:"pp"`
-       DateStr     string `json:"date"`
-}
-
-// Server is a re-runnable HTTP server. Server.Run() may be called repeatedly, 
and
-// each time the previous running server will be stopped, and the server will 
be
-// restarted with the new port address and data request channel.
-type Server struct {
-       stoppableListener          *stoppableListener.StoppableListener
-       stoppableListenerWaitGroup sync.WaitGroup
-}
-
-func (s *Server) registerEndpoints(sm *http.ServeMux, endpoints 
map[string]http.HandlerFunc, staticFileDir string) error {
-       handleRoot, err := s.handleRootFunc(staticFileDir)
-       if err != nil {
-               return fmt.Errorf("Error getting root endpoint: %v", err)
-       }
-       handleSortableJs, err := s.handleSortableFunc(staticFileDir)
-       if err != nil {
-               return fmt.Errorf("Error getting sortable endpoint: %v", err)
-       }
-
-       for path, f := range endpoints {
-               sm.HandleFunc(path, f)
-       }
-
-       sm.HandleFunc("/", handleRoot)
-       sm.HandleFunc("/sorttable.js", handleSortableJs)
-
-       return nil
-}
-
-// Run runs a new HTTP service at the given addr, making data requests to the 
given c.
-// Run may be called repeatedly, and each time, will shut down any existing 
service first.
-// Run is NOT threadsafe, and MUST NOT be called concurrently by multiple 
goroutines.
-func (s *Server) Run(endpoints map[string]http.HandlerFunc, addr string, 
readTimeout time.Duration, writeTimeout time.Duration, staticFileDir string) 
error {
-       if s.stoppableListener != nil {
-               log.Infof("Stopping Web Server\n")
-               s.stoppableListener.Stop()
-               s.stoppableListenerWaitGroup.Wait()
-       }
-       log.Infof("Starting Web Server\n")
-
-       var err error
-       var originalListener net.Listener
-       if originalListener, err = net.Listen("tcp", addr); err != nil {
-               return err
-       }
-       if s.stoppableListener, err = stoppableListener.New(originalListener); 
err != nil {
-               return err
-       }
-
-       sm := http.NewServeMux()
-       err = s.registerEndpoints(sm, endpoints, staticFileDir)
-       if err != nil {
-               return err
-       }
-       server := &http.Server{
-               Addr:           addr,
-               Handler:        sm,
-               ReadTimeout:    readTimeout,
-               WriteTimeout:   writeTimeout,
-               MaxHeaderBytes: 1 << 20,
-       }
-
-       s.stoppableListenerWaitGroup = sync.WaitGroup{}
-       s.stoppableListenerWaitGroup.Add(1)
-       go func() {
-               defer s.stoppableListenerWaitGroup.Done()
-               err := server.Serve(s.stoppableListener)
-               if err != nil {
-                       log.Warnf("HTTP server stopped with error: %v\n", err)
-               }
-       }()
-
-       log.Infof("Web server listening on %s", addr)
-       return nil
-}
-
-// ParametersStr takes the URL query parameters, and returns a string as used 
by the Traffic Monitor 1.0 endpoints "pp" key.
-func ParametersStr(params url.Values) string {
-       pp := ""
-       for param, vals := range params {
-               for _, val := range vals {
-                       pp += param + "=[" + val + "], "
-               }
-       }
-       if len(pp) > 2 {
-               pp = pp[:len(pp)-2]
-       }
-       return pp
-}
-
-//CommonAPIDataDataFormat is a common Date format for the API
-const CommonAPIDataDateFormat = "Mon Jan 02 15:04:05 UTC 2006"
-
-// DateStr returns the given time in the format expected by Traffic Monitor 
1.0 API users
-func DateStr(t time.Time) string {
-       return t.UTC().Format(CommonAPIDataDateFormat)
-}
-
-func (s *Server) handleRootFunc(staticFileDir string) (http.HandlerFunc, 
error) {
-       return s.handleFile(staticFileDir + "/index.html")
-}
-
-func (s *Server) handleSortableFunc(staticFileDir string) (http.HandlerFunc, 
error) {
-       return s.handleFile(staticFileDir + "/sorttable.js")
-}
-
-func (s *Server) handleFile(name string) (http.HandlerFunc, error) {
-       bytes, err := ioutil.ReadFile(name)
-       if err != nil {
-               return nil, err
-       }
-       contentType := http.DetectContentType(bytes)
-       return func(w http.ResponseWriter, req *http.Request) {
-               w.Header().Set("Content-Type", contentType)
-               fmt.Fprintf(w, "%s", bytes)
-       }, nil
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/static/index.html
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/static/index.html 
b/traffic_monitor/experimental/traffic_monitor/static/index.html
deleted file mode 100644
index 66cd03b..0000000
--- a/traffic_monitor/experimental/traffic_monitor/static/index.html
+++ /dev/null
@@ -1,560 +0,0 @@
-<!DOCTYPE html>
-
-<!--
-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.
--->
-
-
-<html>
-       <head>
-               <!-- <script src="sorttable.js"></script> -->
-               <meta charset="UTF-8">
-               <title>Traffic Monitor</title>
-               <style>
-                body {
-                        font-family: "Lato", sans-serif;
-                        font-size: 14px;
-                }
-
-                ul.tab {
-                        list-style-type: none;
-                        margin: 0;
-                        padding: 0;
-                        overflow: hidden;
-                        border: 1px solid #ccc;
-                        background-color: #f1f1f1;
-                }
-
-                ul.tab li {float: left;}
-
-                ul.tab li a {
-                        display: inline-block;
-                        color: black;
-                        text-align: center;
-                        padding: 8px 8px;
-                        text-decoration: none;
-                        transition: 0.3s;
-                }
-
-                ul.tab li a:hover {
-                        background-color: #cfd;
-                }
-
-                .tab-header-selected {
-                        background-color: #adb;
-                }
-
-                .tabcontent {
-                        display: none;
-                        padding: 6px 6px;
-                        border: 1px solid #ccc;
-                        border-top: none;
-                }
-
-                table, th, td {
-                        border: 0px solid black;
-                }
-
-                table {
-                        border-collapse: separate;
-                        border-spacing: 0px 0;
-                        width: 100%;
-                }
-
-                th, td {
-                        padding:5px 20px 5px 5px;
-                }
-
-                th {
-                        white-space: nowrap;
-                }
-
-                tr.stripes:nth-child(even) {
-                        background: #dfe
-                }
-                tr.stripes:nth-child(odd) {
-                        background: #fff
-                }
-
-                li.endpoint {
-                        margin: 4px 0;
-                }
-
-                ul {
-                        list-style: none;
-                }
-
-                #top-bar {
-                        border-collapse: collapse;
-                        border-color: #adb;;
-                        border-width: 0px 0px 1px 0px;
-                        padding-bottom: 10px;
-                }
-
-                .links {
-                        display: table;
-                }
-                .links ul {
-                        display: table-cell;
-                        vertical-align: top;
-                }
-
-                .error {
-                        background-color: #f00;
-                }
-                .warning {
-                        background-color: #f80;
-                }
-               </style>
-               <script>
-                function init() {
-                        openTab('cache-states-content');
-                        getTopBar();
-                        setInterval(getCacheCount, 4755);
-                        setInterval(getCacheAvailableCount, 4800);
-                        setInterval(getBandwidth, 4621);
-                        setInterval(getBandwidthCapacity, 4591);
-                        setInterval(getCacheDownCount, 4832);
-                        setInterval(getVersion, 10007); // change to retry on 
failure, and only do on startup
-                        setInterval(getTrafficOpsUri, 10019); // change to 
retry on failure, and only do on startup
-                        setInterval(getTrafficOpsCdn, 10500); // change to 
retry on failure, and only do on startup
-                        setInterval(getEvents, 2004); // change to retry on 
failure, and only do on startup
-                        setInterval(getCacheStatuses, 5009);
-                        setInterval(getDsStats, 4003);
-                }
-
-                // source: http://stackoverflow.com/a/2901298/292623
-                function numberStrWithCommas(x) {
-                        return x.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-                }
-
-                function openTab(tabName) {
-                        var i, x, tablinks;
-                        x = document.getElementsByClassName("tabcontent");
-                        for (i = 0; i < x.length; i++) {
-                                x[i].style.display = "none";
-                        }
-                        tablinks = document.getElementsByClassName("tablinks");
-                        for (i = 0; i < x.length; i++) {
-                                tablinks[i].className = 
tablinks[i].className.replace(" tab-selected", "");
-                        }
-
-                        tabheaders = 
document.getElementsByClassName("tab-header");
-                        for (i = 0; i < tabheaders.length; i++) {
-                                tabheaders[i].className = 
tabheaders[i].className.replace(" tab-header-selected", "");
-                        }
-
-                        document.getElementById(tabName).style.display = 
"block";
-                        document.getElementById(tabName).className += " 
tab-selected";
-                        document.getElementById(tabName + "-tab").className += 
" tab-header-selected";
-                }
-
-                function getCacheCount() {
-                        ajax("/api/cache-count", function(r) {
-                                
document.getElementById("cache-count").innerHTML = r;
-                        });
-                }
-
-                function getCacheAvailableCount() {
-                        ajax("/api/cache-available-count", function(r) {
-                                
document.getElementById("cache-available").innerHTML = r;
-                        });
-                }
-
-                function getBandwidth() {
-                        ajax("/api/bandwidth-kbps", function(r) {
-                                document.getElementById("bandwidth").innerHTML 
= numberStrWithCommas((parseFloat(r) / kilobitsInGigabit).toFixed(2));
-                        });
-                }
-
-                function getBandwidthCapacity() {
-                        ajax("/api/bandwidth-capacity-kbps", function(r) {
-                                
document.getElementById("bandwidth-capacity").innerHTML = 
numberStrWithCommas((r / kilobitsInGigabit).toString());
-                        });
-                }
-
-                function getCacheDownCount() {
-                        ajax("/api/cache-down-count", function(r) {
-                                
document.getElementById("cache-down").innerHTML = r;
-                        });
-                }
-
-                function getVersion() {
-                        ajax("/api/version", function(r) {
-                                document.getElementById("version").innerHTML = 
r;
-                        });
-                }
-
-                function getTrafficOpsUri() {
-                        ajax("/api/traffic-ops-uri", function(r) {
-                                
document.getElementById("source-uri").innerHTML = "<a href='" + r + "'>" + r + 
"</a>";
-                        });
-                }
-
-
-                function getTrafficOpsCdn() {
-                        ajax("/publish/ConfigDoc", function(r) {
-                                var j = JSON.parse(r);
-                                document.getElementById("cdn-name").innerHTML 
= j.cdnName;
-                        });
-                }
-
-                var lastEvent = 0;
-                function getEvents() {
-                        /// \todo add /api/events-since/{index} (and change 
Traffic Monitor to keep latest
-                        ajax("/publish/EventLog", function(r) {
-                                var jdata = JSON.parse(r);
-                                for (i = jdata.events.length - 1; i >= 0; i--) 
{
-                                        var event = jdata.events[i];
-                                        if (event.index <= lastEvent) {
-                                                continue;
-                                        }
-                                        lastEvent = event.index
-                                        var row = 
document.getElementById("event-log").insertRow(1); 
//document.createElement("tr");
-                                        row.classList.add("stripes");
-                                        row.insertCell(0).id = row.id + 
"-name";
-                                        document.getElementById(row.id + 
"-name").textContent = event.name;
-                                        document.getElementById(row.id + 
"-name").style.whiteSpace = "nowrap";
-                                        row.insertCell(1).textContent = 
event.type;
-                                        row.insertCell(2).textContent = 
event.isAvailable ? "available" : "offline";
-                                        if(event.isAvailable) {
-                                                row.classList.add("stripes");
-                                                row.classList.remove("error");
-                                        } else {
-                                                row.classList.add("error");
-                                                
row.classList.remove("stripes");
-                                        }
-                                        row.insertCell(3).textContent = 
event.description;
-                                        row.insertCell(4).id = row.id + 
"-last";
-                                        document.getElementById(row.id + 
"-last").textContent = new Date(event.time * 1000).toISOString();
-                                        document.getElementById(row.id + 
"-last").style.whiteSpace = "nowrap";
-                                        document.getElementById(row.id + 
"-last").style.textAlign = "right";
-                                }
-                        });
-                }
-
-                function getCacheStates() {
-                        ajax("/api/cache-statuses", function(r) {
-                                var jdata = JSON.parse(r);
-                                var servers = Object.keys(jdata); //debug
-                                for (i = 0; i < servers.length; i++) {
-                                        var server = servers[i];
-                                        if 
(!document.getElementById("cache-states-" + server)) {
-                                                var row = 
document.getElementById("cache-states").insertRow(1); 
//document.createElement("tr");
-                                                row.classList.add("stripes");
-                                                row.id = "cache-states-" + 
server
-                                                row.insertCell(0).id = row.id 
+ "-server";
-                                                row.insertCell(1).id = row.id 
+ "-type";
-                                                row.insertCell(2).id = row.id 
+ "-status";
-                                                row.insertCell(3).id = row.id 
+ "-load-average";
-                                                row.insertCell(4).id = row.id 
+ "-query-time";
-                                                row.insertCell(5).id = row.id 
+ "-health-time";
-                                                row.insertCell(6).id = row.id 
+ "-stat-time";
-                                                row.insertCell(7).id = row.id 
+ "-health-span";
-                                                row.insertCell(8).id = row.id 
+ "-stat-span";
-                                                row.insertCell(9).id = row.id 
+ "-bandwidth";
-                                                row.insertCell(10).id = row.id 
+ "-connection-count";
-                                                document.getElementById(row.id 
+ "-server").textContent = server;
-                                                document.getElementById(row.id 
+ "-server").style.whiteSpace = "nowrap";
-                                                document.getElementById(row.id 
+ "-load-average").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-query-time").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-health-time").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-stat-time").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-health-span").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-stat-span").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-bandwidth").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-connection-count").style.textAlign = "right";
-                                        }
-
-                                        /* \todo change to iterate over 
members, and make cells id constructed from these*/
-                                        if 
(jdata[server].hasOwnProperty("type")) {
-                                                
document.getElementById("cache-states-" + server + "-type").textContent = 
jdata[server].type;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("status")) {
-                                                
document.getElementById("cache-states-" + server + "-status").textContent = 
jdata[server].status;
-                                                var row = 
document.getElementById("cache-states-" + server);
-                                                if 
(jdata[server].status.indexOf("ADMIN_DOWN") != -1) {
-                                                        
row.classList.add("warning");
-                                                        
row.classList.remove("error");
-                                                        
row.classList.remove("stripes");
-                                                } else if 
(jdata[server].status.indexOf(" available") == -1) {
-                                                        
row.classList.add("error");
-                                                        
row.classList.remove("warning");
-                                                        
row.classList.remove("stripes");
-                                                } else {
-                                                        
row.classList.add("stripe");
-                                                        
row.classList.remove("warning");
-                                                        
row.classList.remove("error");
-                                                }
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("load_average")) {
-                                                
document.getElementById("cache-states-" + server + "-load-average").textContent 
= jdata[server].load_average;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("query_time_ms")) {
-                                                
document.getElementById("cache-states-" + server + "-query-time").textContent = 
jdata[server].query_time_ms;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("health_time_ms")) {
-                                                
document.getElementById("cache-states-" + server + "-health-time").textContent 
= jdata[server].health_time_ms;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("stat_time_ms")) {
-                                                
document.getElementById("cache-states-" + server + "-stat-time").textContent = 
jdata[server].stat_time_ms;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("health_span_ms")) {
-                                                
document.getElementById("cache-states-" + server + "-health-span").textContent 
= jdata[server].health_span_ms;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("stat_span_ms")) {
-                                                
document.getElementById("cache-states-" + server + "-stat-span").textContent = 
jdata[server].stat_span_ms;
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("bandwidth_kbps")) {
-                                                var kbps = 
(jdata[server].bandwidth_kbps / kilobitsInMegabit).toFixed(2);
-                                                var max = 
numberStrWithCommas((jdata[server].bandwidth_capacity_kbps / 
kilobitsInMegabit).toFixed(0));
-                                                
document.getElementById("cache-states-" + server + "-bandwidth").textContent = 
'' + kbps + ' / ' + max;
-                                        } else {
-                                                
document.getElementById("cache-states-" + server + "-bandwidth").textContent = 
"N/A";
-                                        }
-                                        if 
(jdata[server].hasOwnProperty("connection_count")) {
-                                                
document.getElementById("cache-states-" + server + 
"-connection-count").textContent = jdata[server].connection_count;
-                                        } else {
-                                                
document.getElementById("cache-states-" + server + 
"-connection-count").textContent = "N/A";
-                                        }
-                                }
-                        })
-                }
-
-                var millisecondsInSecond = 1000;
-                var kilobitsInGigabit = 1000000;
-                var kilobitsInMegabit = 1000;
-
-                // dsDisplayFloat takes a float, and returns the string to 
display. For nonzero values, it returns two decimal places. For zero values, it 
returns an empty string, to make nonzero values more visible.
-                function dsDisplayFloat(f) {
-                        var s = f
-                        if (f != 0.0) {
-                                s = f.toFixed(2);
-                        }
-                        return s
-                }
-
-                function getDsStats() {
-                        var now = Date.now();
-
-                        /// \todo add /api/delivery-service-stats which only 
returns the data needed by the UI, for efficiency
-                        ajax("/publish/DsStats", function(r) {
-                                var j = JSON.parse(r);
-                                var jds = j.deliveryService
-                                var deliveryServiceNames = Object.keys(jds); 
//debug
-                                //decrementing for loop so DsNames are 
alphabetical A-Z
-                                //TODO allow for filtering of columns so this 
isn't necessary
-                                       for (var i = 
deliveryServiceNames.length - 1; i >= 0; i--) {
-                                        var deliveryService = 
deliveryServiceNames[i];
-
-                                        if 
(!document.getElementById("deliveryservice-stats-" + deliveryService)) {
-                                                var row = 
document.getElementById("deliveryservice-stats").insertRow(1); 
//document.createElement("tr");
-                                                row.id = 
"deliveryservice-stats-" + deliveryService
-                                                row.insertCell(0).id = row.id 
+ "-delivery-service";
-                                                row.insertCell(1).id = row.id 
+ "-status";
-                                                row.insertCell(2).id = row.id 
+ "-caches-reporting";
-                                                row.insertCell(3).id = row.id 
+ "-bandwidth";
-                                                row.insertCell(4).id = row.id 
+ "-tps";
-                                                row.insertCell(5).id = row.id 
+ "-2xx";
-                                                row.insertCell(6).id = row.id 
+ "-3xx";
-                                                row.insertCell(7).id = row.id 
+ "-4xx";
-                                                row.insertCell(8).id = row.id 
+ "-5xx";
-                                                row.insertCell(9).id = row.id 
+ "-disabled-locations";
-                                                document.getElementById(row.id 
+ "-delivery-service").textContent = deliveryService;
-                                                document.getElementById(row.id 
+ "-delivery-service").style.whiteSpace = "nowrap";
-                                                document.getElementById(row.id 
+ "-caches-reporting").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-bandwidth").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-tps").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-2xx").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-3xx").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-4xx").style.textAlign = "right";
-                                                document.getElementById(row.id 
+ "-5xx").style.textAlign = "right";
-                                        }
-
-                                        // \todo check that array has a member 
before dereferencing [0]
-                                        if 
(jds[deliveryService].hasOwnProperty("isAvailable")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-status").textContent = jds[deliveryService]["isAvailable"][0].value == "true" 
? "available" : "unavailable - " + 
jds[deliveryService]["error-string"][0].value;
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("caches-reporting") && 
jds[deliveryService].hasOwnProperty("caches-available") && 
jds[deliveryService].hasOwnProperty("caches-configured")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-caches-reporting").textContent = 
jds[deliveryService]['caches-reporting'][0].value + " / " + 
jds[deliveryService]['caches-available'][0].value + " / " + 
jds[deliveryService]['caches-configured'][0].value;
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.kbps")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-bandwidth").textContent = (jds[deliveryService]['total.kbps'][0].value / 
kilobitsInMegabit).toFixed(2);
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-bandwidth").textContent = "N/A";
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.tps_total")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-tps").textContent = 
dsDisplayFloat(parseFloat(jds[deliveryService]['total.tps_total'][0].value));
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-tps").textContent = "N/A";
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.tps_2xx")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-2xx").textContent = 
dsDisplayFloat(parseFloat(jds[deliveryService]['total.tps_2xx'][0].value));
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-2xx").textContent = "N/A";
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.tps_3xx")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-3xx").textContent = 
dsDisplayFloat(parseFloat(jds[deliveryService]['total.tps_3xx'][0].value));
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-3xx").textContent = "N/A";
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.tps_4xx")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-4xx").textContent = 
dsDisplayFloat(parseFloat(jds[deliveryService]['total.tps_4xx'][0].value));
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-4xx").textContent = "N/A";
-                                        }
-                                        if 
(jds[deliveryService].hasOwnProperty("total.tps_5xx")) {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-5xx").textContent = 
dsDisplayFloat(parseFloat(jds[deliveryService]['total.tps_5xx'][0].value));
-                                        } else {
-                                                
document.getElementById("deliveryservice-stats-" + deliveryService + 
"-5xx").textContent = "N/A";
-                                        }
-
-                                        // \todo implement disabled locations
-
-                                        var row = 
document.getElementById("deliveryservice-stats-" + deliveryService);
-                                        if 
(jds[deliveryService]["isAvailable"][0].value == "true") {
-                                                row.classList.add("stripes");
-                                                row.classList.remove("error");
-                                        } else {
-                                                row.classList.add("error");
-                                                
row.classList.remove("stripes");
-                                        }
-                                }
-                        })
-                }
-
-                function getCacheStatuses() {
-                        getCacheCount();
-                        getCacheAvailableCount();
-                        getCacheDownCount();
-                        getCacheStates();
-                }
-
-                function getTopBar() {
-                        getVersion();
-                        getTrafficOpsUri();
-                        getTrafficOpsCdn();
-                        getCacheStatuses();
-                }
-
-                function ajax(endpoint, f) {
-                        var xhttp = new XMLHttpRequest();
-                        xhttp.onreadystatechange = function() {
-                                if (xhttp.readyState == 4 && xhttp.status == 
200) {
-                                        f(xhttp.responseText);
-                                }
-                        };
-                        xhttp.open("GET", endpoint, true);
-                        xhttp.send();
-                }
-               </script>
-       </head>
-       <body onload="init()">
-
-               <table id="top-bar">
-                       <tr>
-                               <td>Caches: count=<span 
id="cache-count">0</span> available=<span id="cache-available">0</span> 
down=<span id="cache-down">0</span> </td>
-                               <td>Bandwidth: <span id="bandwidth">0</span> / 
<span id="bandwidth-capacity">∞</span> gbps</td>
-                               <td>Traffic Ops: <span 
id="source-uri">unknown</span></td>
-                               <td>CDN: <span id="cdn-name">unknown</span></td>
-                               <td>Version: <span 
id="version">unknown</span></td>
-                       </tr>
-               </table>
-
-               <div class="links">
-                       <ul>
-                               <li class="endpoint"><a 
href="/publish/EventLog">EventLog</a></li>
-                               <li class="endpoint"><a 
href="/publish/CacheStats">CacheStats</a></li>
-                               <li class="endpoint"><a 
href="/publish/DsStats">DsStats</a></li>
-                               <li class="endpoint"><a 
href="/publish/CrStates">CrStates (as published to Traffic Routers)</a></li>
-                               <li class="endpoint"><a 
href="/publish/CrConfig">CrConfig (json)</a></li>
-                               <li class="endpoint"><a 
href="/publish/PeerStates">PeerStates</a></li>
-                               <li class="endpoint"><a 
href="/publish/Stats">Stats</a></li>
-                               <li class="endpoint"><a 
href="/publish/StatSummary">StatSummary</a></li>
-                               <li class="endpoint"><a 
href="/publish/ConfigDoc">ConfigDoc</a></li>
-                       </ul>
-
-                       <ul>
-                               <li class="endpoint"><a 
href="/api/cache-count">/api/cache-count</a></li>
-                               <li class="endpoint"><a 
href="/api/cache-available-count">/api/cache-available-count</a></li>
-                               <li class="endpoint"><a 
href="/api/cache-down-count">/api/cache-down-count</a></li>
-                               <li class="endpoint"><a 
href="/api/version">/api/version</a></li>
-                               <li class="endpoint"><a 
href="/api/traffic-ops-uri">/api/traffic-ops-uri</a></li>
-                               <li class="endpoint"><a 
href="/api/cache-statuses">/api/cache-statuses</a></li>
-                               <li class="endpoint"><a 
href="/api/bandwidth-kbps">/api/bandwidth-kbps</a></li>
-                               <li class="endpoint"><a 
href="/api/bandwidth-capacity-kbps">/api/bandwidth-capacity-kbps</a></li>
-                       </ul>
-               </div>
-
-               <ul class="tab">
-                       <li id="cache-states-content-tab" class="tab-header"><a 
href="#" onclick="openTab('cache-states-content')" class="tablinks">Cache 
States</a></li>
-                       <li id="deliveryservice-stats-content-tab" 
class="tab-header"><a href="#" 
onclick="openTab('deliveryservice-stats-content')" class="tablinks">Delivery 
Service States</a></li>
-                       <li id="event-log-content-tab" class="tab-header"><a 
href="#" onclick="openTab('event-log-content')" class="tablinks">Event 
Log</a></li>
-               </ul>
-
-               <div id="cache-states-content" class="tabcontent">
-                       <table id="cache-states" class="tab-grid sortable">
-                               <tr>
-                                       <th>Server</th>
-                                       <th>Type</th>
-                                       <th>Status</th>
-                                       <th align="right">Load Average</th>
-                                       <th align="right">Query Time (ms)</th>
-                                       <th align="right">Health Time (ms)</th>
-                                       <th align="right">Stat Time (ms)</th>
-                                       <th align="right">Health Span (ms)</th>
-                                       <th align="right">Stat Span (ms)</th>
-                                       <th align="right">Bandwidth (mbps)</th>
-                                       <th align="right">Connection Count</th>
-                               </tr>
-                       </table>
-               </div>
-               <div id="deliveryservice-stats-content" class="tabcontent">
-                       <table id="deliveryservice-stats" class="tab-grid 
sortable">
-                               <tr>
-                                       <th>Delivery Service</th>
-                                       <th>Status</th>
-                                       <th align="right">Caches 
Reporting/Available/Configured</th>
-                                       <th align="right">Bandwidth (mbps)</th>
-                                       <th align="right">t/sec</th>
-                                       <th align="right">2xx/sec</th>
-                                       <th align="right">3xx/sec</th>
-                                       <th align="right">4xx/sec</th>
-                                       <th align="right">5xx/sec</th>
-                                       <th>Disabled Locations</th>
-                               </tr>
-                       </table>
-               </div>
-
-               <div id="event-log-content" class="tabcontent">
-                       <table id="event-log" class="tab-grid sortable">
-                               <tr>
-                                       <th>Name</th>
-                                       <th>Type</th>
-                                       <th>Status</th>
-                                       <th>Description</th>
-                                       <th align="center" 
id="event-log-last-header">Event Time</th>
-                               </tr>
-                       </table>
-               </div>
-
-               <div id="update-num-text">Number of updates: <span 
id="update-num">0</span></div>
-               <div id="last-val-text">Last Val: <span 
id="last-val">0</span></div>
-               <a href="/">Refresh Server List</a>
-       </body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/static/sorttable.js
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/static/sorttable.js 
b/traffic_monitor/experimental/traffic_monitor/static/sorttable.js
deleted file mode 100644
index 38b0fc6..0000000
--- a/traffic_monitor/experimental/traffic_monitor/static/sorttable.js
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
-  SortTable
-  version 2
-  7th April 2007
-  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
-
-  Instructions:
-  Download this file
-  Add <script src="sorttable.js"></script> to your HTML
-  Add class="sortable" to any table you'd like to make sortable
-  Click on the headers to sort
-
-  Thanks to many, many people for contributions and suggestions.
-  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
-  This basically means: do what you want with it.
-*/
-
-
-var stIsIE = /*@cc_on!@*/false;
-
-sorttable = {
-  init: function() {
-    // quit if this function has already been called
-    if (arguments.callee.done) return;
-    // flag this function so we don't do the same thing twice
-    arguments.callee.done = true;
-    // kill the timer
-    if (_timer) clearInterval(_timer);
-
-    if (!document.createElement || !document.getElementsByTagName) return;
-
-    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
-
-    forEach(document.getElementsByTagName('table'), function(table) {
-      if (table.className.search(/\bsortable\b/) != -1) {
-        sorttable.makeSortable(table);
-      }
-    });
-
-  },
-
-  makeSortable: function(table) {
-    if (table.getElementsByTagName('thead').length == 0) {
-      // table doesn't have a tHead. Since it should have, create one and
-      // put the first table row in it.
-      the = document.createElement('thead');
-      the.appendChild(table.rows[0]);
-      table.insertBefore(the,table.firstChild);
-    }
-    // Safari doesn't support table.tHead, sigh
-    if (table.tHead == null) table.tHead = 
table.getElementsByTagName('thead')[0];
-
-    if (table.tHead.rows.length != 1) return; // can't cope with two header 
rows
-
-    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
-    // "total" rows, for example). This is B&R, since what you're supposed
-    // to do is put them in a tfoot. So, if there are sortbottom rows,
-    // for backwards compatibility, move them to tfoot (creating it if needed).
-    sortbottomrows = [];
-    for (var i=0; i<table.rows.length; i++) {
-      if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
-        sortbottomrows[sortbottomrows.length] = table.rows[i];
-      }
-    }
-    if (sortbottomrows) {
-      if (table.tFoot == null) {
-        // table doesn't have a tfoot. Create one.
-        tfo = document.createElement('tfoot');
-        table.appendChild(tfo);
-      }
-      for (var i=0; i<sortbottomrows.length; i++) {
-        tfo.appendChild(sortbottomrows[i]);
-      }
-      delete sortbottomrows;
-    }
-
-    // work through each column and calculate its type
-    headrow = table.tHead.rows[0].cells;
-    for (var i=0; i<headrow.length; i++) {
-      // manually override the type with a sorttable_type attribute
-      if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this 
col
-        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
-        if (mtch) { override = mtch[1]; }
-             if (mtch && typeof sorttable["sort_"+override] == 'function') {
-               headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
-             } else {
-               headrow[i].sorttable_sortfunction = 
sorttable.guessType(table,i);
-             }
-             // make it clickable to sort
-             headrow[i].sorttable_columnindex = i;
-             headrow[i].sorttable_tbody = table.tBodies[0];
-             dean_addEvent(headrow[i],"click", sorttable.innerSortFunction = 
function(e) {
-
-          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
-            // if we're already sorted by this column, just
-            // reverse the table, which is quicker
-            sorttable.reverse(this.sorttable_tbody);
-            this.className = this.className.replace('sorttable_sorted',
-                                                    
'sorttable_sorted_reverse');
-            this.removeChild(document.getElementById('sorttable_sortfwdind'));
-            sortrevind = document.createElement('span');
-            sortrevind.id = "sorttable_sortrevind";
-            sortrevind.innerHTML = stIsIE ? '&nbsp<font 
face="webdings">5</font>' : '&nbsp;&#x25B4;';
-            this.appendChild(sortrevind);
-            return;
-          }
-          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
-            // if we're already sorted by this column in reverse, just
-            // re-reverse the table, which is quicker
-            sorttable.reverse(this.sorttable_tbody);
-            this.className = this.className.replace('sorttable_sorted_reverse',
-                                                    'sorttable_sorted');
-            this.removeChild(document.getElementById('sorttable_sortrevind'));
-            sortfwdind = document.createElement('span');
-            sortfwdind.id = "sorttable_sortfwdind";
-            sortfwdind.innerHTML = stIsIE ? '&nbsp<font 
face="webdings">6</font>' : '&nbsp;&#x25BE;';
-            this.appendChild(sortfwdind);
-            return;
-          }
-
-          // remove sorttable_sorted classes
-          theadrow = this.parentNode;
-          forEach(theadrow.childNodes, function(cell) {
-            if (cell.nodeType == 1) { // an element
-              cell.className = 
cell.className.replace('sorttable_sorted_reverse','');
-              cell.className = cell.className.replace('sorttable_sorted','');
-            }
-          });
-          sortfwdind = document.getElementById('sorttable_sortfwdind');
-          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
-          sortrevind = document.getElementById('sorttable_sortrevind');
-          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
-
-          this.className += ' sorttable_sorted';
-          sortfwdind = document.createElement('span');
-          sortfwdind.id = "sorttable_sortfwdind";
-          sortfwdind.innerHTML = stIsIE ? '&nbsp<font 
face="webdings">6</font>' : '&nbsp;&#x25BE;';
-          this.appendChild(sortfwdind);
-
-               // build an array to sort. This is a Schwartzian transform 
thing,
-               // i.e., we "decorate" each row with the actual sort key,
-               // sort based on the sort keys, and then put the rows back in 
order
-               // which is a lot faster because you only do getInnerText once 
per row
-               row_array = [];
-               col = this.sorttable_columnindex;
-               rows = this.sorttable_tbody.rows;
-               for (var j=0; j<rows.length; j++) {
-                 row_array[row_array.length] = 
[sorttable.getInnerText(rows[j].cells[col]), rows[j]];
-               }
-               /* If you want a stable sort, uncomment the following line */
-               //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
-               /* and comment out this one */
-               row_array.sort(this.sorttable_sortfunction);
-
-               tb = this.sorttable_tbody;
-               for (var j=0; j<row_array.length; j++) {
-                 tb.appendChild(row_array[j][1]);
-               }
-
-               delete row_array;
-             });
-           }
-    }
-  },
-
-  guessType: function(table, column) {
-    // guess the type of a column based on its first non-blank row
-    sortfn = sorttable.sort_alpha;
-    for (var i=0; i<table.tBodies[0].rows.length; i++) {
-      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
-      if (text != '') {
-        if (text.match(/^-?[�$�]?[\d,.]+%?$/)) {
-          return sorttable.sort_numeric;
-        }
-        // check for a date: dd/mm/yyyy or dd/mm/yy
-        // can have / or . or - as separator
-        // can be mm/dd as well
-        possdate = text.match(sorttable.DATE_RE)
-        if (possdate) {
-          // looks like a date
-          first = parseInt(possdate[1]);
-          second = parseInt(possdate[2]);
-          if (first > 12) {
-            // definitely dd/mm
-            return sorttable.sort_ddmm;
-          } else if (second > 12) {
-            return sorttable.sort_mmdd;
-          } else {
-            // looks like a date, but we can't tell which, so assume
-            // that it's dd/mm (English imperialism!) and keep looking
-            sortfn = sorttable.sort_ddmm;
-          }
-        }
-      }
-    }
-    return sortfn;
-  },
-
-  getInnerText: function(node) {
-    // gets the text we want to use for sorting for a cell.
-    // strips leading and trailing whitespace.
-    // this is *not* a generic getInnerText function; it's special to 
sorttable.
-    // for example, you can override the cell text with a customkey attribute.
-    // it also gets .value for <input> fields.
-
-    if (!node) return "";
-
-    hasInputs = (typeof node.getElementsByTagName == 'function') &&
-                 node.getElementsByTagName('input').length;
-
-    if (node.getAttribute("sorttable_customkey") != null) {
-      return node.getAttribute("sorttable_customkey");
-    }
-    else if (typeof node.textContent != 'undefined' && !hasInputs) {
-      return node.textContent.replace(/^\s+|\s+$/g, '');
-    }
-    else if (typeof node.innerText != 'undefined' && !hasInputs) {
-      return node.innerText.replace(/^\s+|\s+$/g, '');
-    }
-    else if (typeof node.text != 'undefined' && !hasInputs) {
-      return node.text.replace(/^\s+|\s+$/g, '');
-    }
-    else {
-      switch (node.nodeType) {
-        case 3:
-          if (node.nodeName.toLowerCase() == 'input') {
-            return node.value.replace(/^\s+|\s+$/g, '');
-          }
-        case 4:
-          return node.nodeValue.replace(/^\s+|\s+$/g, '');
-          break;
-        case 1:
-        case 11:
-          var innerText = '';
-          for (var i = 0; i < node.childNodes.length; i++) {
-            innerText += sorttable.getInnerText(node.childNodes[i]);
-          }
-          return innerText.replace(/^\s+|\s+$/g, '');
-          break;
-        default:
-          return '';
-      }
-    }
-  },
-
-  reverse: function(tbody) {
-    // reverse the rows in a tbody
-    newrows = [];
-    for (var i=0; i<tbody.rows.length; i++) {
-      newrows[newrows.length] = tbody.rows[i];
-    }
-    for (var i=newrows.length-1; i>=0; i--) {
-       tbody.appendChild(newrows[i]);
-    }
-    delete newrows;
-  },
-
-  /* sort functions
-     each sort function takes two parameters, a and b
-     you are comparing a[0] and b[0] */
-  sort_numeric: function(a,b) {
-    aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
-    if (isNaN(aa)) aa = 0;
-    bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
-    if (isNaN(bb)) bb = 0;
-    return aa-bb;
-  },
-  sort_alpha: function(a,b) {
-    if (a[0]==b[0]) return 0;
-    if (a[0]<b[0]) return -1;
-    return 1;
-  },
-  sort_ddmm: function(a,b) {
-    mtch = a[0].match(sorttable.DATE_RE);
-    y = mtch[3]; m = mtch[2]; d = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt1 = y+m+d;
-    mtch = b[0].match(sorttable.DATE_RE);
-    y = mtch[3]; m = mtch[2]; d = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt2 = y+m+d;
-    if (dt1==dt2) return 0;
-    if (dt1<dt2) return -1;
-    return 1;
-  },
-  sort_mmdd: function(a,b) {
-    mtch = a[0].match(sorttable.DATE_RE);
-    y = mtch[3]; d = mtch[2]; m = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt1 = y+m+d;
-    mtch = b[0].match(sorttable.DATE_RE);
-    y = mtch[3]; d = mtch[2]; m = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt2 = y+m+d;
-    if (dt1==dt2) return 0;
-    if (dt1<dt2) return -1;
-    return 1;
-  },
-
-  shaker_sort: function(list, comp_func) {
-    // A stable sort function to allow multi-level sorting of data
-    // see: http://en.wikipedia.org/wiki/Cocktail_sort
-    // thanks to Joseph Nahmias
-    var b = 0;
-    var t = list.length - 1;
-    var swap = true;
-
-    while(swap) {
-        swap = false;
-        for(var i = b; i < t; ++i) {
-            if ( comp_func(list[i], list[i+1]) > 0 ) {
-                var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
-                swap = true;
-            }
-        } // for
-        t--;
-
-        if (!swap) break;
-
-        for(var i = t; i > b; --i) {
-            if ( comp_func(list[i], list[i-1]) < 0 ) {
-                var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
-                swap = true;
-            }
-        } // for
-        b++;
-
-    } // while(swap)
-  }
-}
-
-/* ******************************************************************
-   Supporting functions: bundled here to avoid depending on a library
-   ****************************************************************** */
-
-// Dean Edwards/Matthias Miller/John Resig
-
-/* for Mozilla/Opera9 */
-if (document.addEventListener) {
-    document.addEventListener("DOMContentLoaded", sorttable.init, false);
-}
-
-/* for Internet Explorer */
-/*@cc_on @*/
-/*@if (@_win32)
-    document.write("<script id=__ie_onload defer 
src=javascript:void(0)><\/script>");
-    var script = document.getElementById("__ie_onload");
-    script.onreadystatechange = function() {
-        if (this.readyState == "complete") {
-            sorttable.init(); // call the onload handler
-        }
-    };
-/*@end @*/
-
-/* for Safari */
-if (/WebKit/i.test(navigator.userAgent)) { // sniff
-    var _timer = setInterval(function() {
-        if (/loaded|complete/.test(document.readyState)) {
-            sorttable.init(); // call the onload handler
-        }
-    }, 10);
-}
-
-/* for other browsers */
-window.onload = sorttable.init;
-
-// written by Dean Edwards, 2005
-// with input from Tino Zijdel, Matthias Miller, Diego Perini
-
-// http://dean.edwards.name/weblog/2005/10/add-event/
-
-function dean_addEvent(element, type, handler) {
-       if (element.addEventListener) {
-               element.addEventListener(type, handler, false);
-       } else {
-               // assign each event handler a unique ID
-               if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
-               // create a hash table of event types for the element
-               if (!element.events) element.events = {};
-               // create a hash table of event handlers for each element/event 
pair
-               var handlers = element.events[type];
-               if (!handlers) {
-                       handlers = element.events[type] = {};
-                       // store the existing event handler (if there is one)
-                       if (element["on" + type]) {
-                               handlers[0] = element["on" + type];
-                       }
-               }
-               // store the event handler in the hash table
-               handlers[handler.$$guid] = handler;
-               // assign a global event handler to do all the work
-               element["on" + type] = handleEvent;
-       }
-};
-// a counter used to create unique IDs
-dean_addEvent.guid = 1;
-
-function removeEvent(element, type, handler) {
-       if (element.removeEventListener) {
-               element.removeEventListener(type, handler, false);
-       } else {
-               // delete the event handler from the hash table
-               if (element.events && element.events[type]) {
-                       delete element.events[type][handler.$$guid];
-               }
-       }
-};
-
-function handleEvent(event) {
-       var returnValue = true;
-       // grab the event object (IE uses a global event object)
-       event = event || fixEvent(((this.ownerDocument || this.document || 
this).parentWindow || window).event);
-       // get a reference to the hash table of event handlers
-       var handlers = this.events[event.type];
-       // execute each event handler
-       for (var i in handlers) {
-               this.$$handleEvent = handlers[i];
-               if (this.$$handleEvent(event) === false) {
-                       returnValue = false;
-               }
-       }
-       return returnValue;
-};
-
-function fixEvent(event) {
-       // add W3C standard event methods
-       event.preventDefault = fixEvent.preventDefault;
-       event.stopPropagation = fixEvent.stopPropagation;
-       return event;
-};
-fixEvent.preventDefault = function() {
-       this.returnValue = false;
-};
-fixEvent.stopPropagation = function() {
-  this.cancelBubble = true;
-}
-
-// Dean's forEach: http://dean.edwards.name/base/forEach.js
-/*
-       forEach, version 1.0
-       Copyright 2006, Dean Edwards
-       License: http://www.opensource.org/licenses/mit-license.php
-*/
-
-// array-like enumeration
-if (!Array.forEach) { // mozilla already supports this
-       Array.forEach = function(array, block, context) {
-               for (var i = 0; i < array.length; i++) {
-                       block.call(context, array[i], i, array);
-               }
-       };
-}
-
-// generic enumeration
-Function.prototype.forEach = function(object, block, context) {
-       for (var key in object) {
-               if (typeof this.prototype[key] == "undefined") {
-                       block.call(context, object[key], key, object);
-               }
-       }
-};
-
-// character enumeration
-String.forEach = function(string, block, context) {
-       Array.forEach(string.split(""), function(chr, index) {
-               block.call(context, chr, index, string);
-       });
-};
-
-// globally resolve forEach enumeration
-var forEach = function(object, block, context) {
-       if (object) {
-               var resolve = Object; // default
-               if (object instanceof Function) {
-                       // functions have a "length" property
-                       resolve = Function;
-               } else if (object.forEach instanceof Function) {
-                       // the object implements a custom forEach method so use 
that
-                       object.forEach(block, context);
-                       return;
-               } else if (typeof object == "string") {
-                       // the object is a string
-                       resolve = String;
-               } else if (typeof object.length == "number") {
-                       // the object is array-like
-                       resolve = Array;
-               }
-               resolve.forEach(object, block, context);
-       }
-};
-

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/threadsafe/cacheavailablestatus.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor/experimental/traffic_monitor/threadsafe/cacheavailablestatus.go
 
b/traffic_monitor/experimental/traffic_monitor/threadsafe/cacheavailablestatus.go
deleted file mode 100644
index edf7b37..0000000
--- 
a/traffic_monitor/experimental/traffic_monitor/threadsafe/cacheavailablestatus.go
+++ /dev/null
@@ -1,52 +0,0 @@
-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 (
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-       "sync"
-)
-
-// CacheAvailableStatus wraps a map of cache available statuses to be safe for 
multiple reader goroutines and one writer.
-type CacheAvailableStatus struct {
-       caches *cache.AvailableStatuses
-       m      *sync.RWMutex
-}
-
-// NewCacheAvailableStatus creates and returns a new CacheAvailableStatus, 
initializing internal pointer values.
-func NewCacheAvailableStatus() CacheAvailableStatus {
-       c := cache.AvailableStatuses(map[enum.CacheName]cache.AvailableStatus{})
-       return CacheAvailableStatus{m: &sync.RWMutex{}, caches: &c}
-}
-
-// Get returns the internal map of cache statuses. The returned map MUST NOT 
be modified. If modification is necessary, copy.
-func (o *CacheAvailableStatus) Get() cache.AvailableStatuses {
-       o.m.RLock()
-       defer o.m.RUnlock()
-       return *o.caches
-}
-
-// Set sets the internal map of cache availability. This MUST NOT be called by 
multiple goroutines.
-func (o *CacheAvailableStatus) Set(v cache.AvailableStatuses) {
-       o.m.Lock()
-       *o.caches = v
-       o.m.Unlock()
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/threadsafe/cachemaxkbpses.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor/experimental/traffic_monitor/threadsafe/cachemaxkbpses.go 
b/traffic_monitor/experimental/traffic_monitor/threadsafe/cachemaxkbpses.go
deleted file mode 100644
index 5bb584c..0000000
--- a/traffic_monitor/experimental/traffic_monitor/threadsafe/cachemaxkbpses.go
+++ /dev/null
@@ -1,52 +0,0 @@
-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 (
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
-       
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
-       "sync"
-)
-
-// CacheAvailableStatus wraps a map of cache available statuses to be safe for 
multiple reader goroutines and one writer.
-type CacheKbpses struct {
-       v *cache.Kbpses
-       m *sync.RWMutex
-}
-
-// NewCacheAvailableStatus creates and returns a new CacheAvailableStatus, 
initializing internal pointer values.
-func NewCacheKbpses() CacheKbpses {
-       v := cache.Kbpses(map[enum.CacheName]int64{})
-       return CacheKbpses{m: &sync.RWMutex{}, v: &v}
-}
-
-// Get returns the internal map of cache statuses. The returned map MUST NOT 
be modified. If modification is necessary, copy.
-func (o *CacheKbpses) Get() cache.Kbpses {
-       o.m.RLock()
-       defer o.m.RUnlock()
-       return *o.v
-}
-
-// Set sets the internal map of cache availability. This MUST NOT be called by 
multiple goroutines.
-func (o *CacheKbpses) Set(v cache.Kbpses) {
-       o.m.Lock()
-       *o.v = v
-       o.m.Unlock()
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/threadsafe/dsstats.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/threadsafe/dsstats.go 
b/traffic_monitor/experimental/traffic_monitor/threadsafe/dsstats.go
deleted file mode 100644
index a13c01a..0000000
--- a/traffic_monitor/experimental/traffic_monitor/threadsafe/dsstats.go
+++ /dev/null
@@ -1,57 +0,0 @@
-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"
-
-       dsdata 
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
-)
-
-// DSStats wraps a deliveryservice.Stats object to be safe for multiple reader 
goroutines and a single writer.
-type DSStats struct {
-       dsStats *dsdata.Stats
-       m       *sync.RWMutex
-}
-
-// DSStatsReader permits reading of a dsdata.Stats object, but not writing. 
This is designed so a Stats object can safely be passed to multiple goroutines, 
without worry one may unsafely write.
-type DSStatsReader interface {
-       Get() dsdata.StatsReadonly
-}
-
-// NewDSStats returns a deliveryservice.Stats object wrapped to be safe for 
multiple readers and a single writer.
-func NewDSStats() DSStats {
-       s := dsdata.NewStats()
-       return DSStats{m: &sync.RWMutex{}, dsStats: &s}
-}
-
-// Get returns a Stats object safe for reading by multiple goroutines
-func (o *DSStats) Get() dsdata.StatsReadonly {
-       o.m.RLock()
-       defer o.m.RUnlock()
-       return *o.dsStats
-}
-
-// Set sets the internal Stats object. This MUST NOT be called by multiple 
goroutines.
-func (o *DSStats) Set(newDsStats dsdata.Stats) {
-       o.m.Lock()
-       *o.dsStats = newDsStats
-       o.m.Unlock()
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/594b8517/traffic_monitor/experimental/traffic_monitor/threadsafe/lastkbpsstats.go
----------------------------------------------------------------------
diff --git 
a/traffic_monitor/experimental/traffic_monitor/threadsafe/lastkbpsstats.go 
b/traffic_monitor/experimental/traffic_monitor/threadsafe/lastkbpsstats.go
deleted file mode 100644
index 610b8a9..0000000
--- a/traffic_monitor/experimental/traffic_monitor/threadsafe/lastkbpsstats.go
+++ /dev/null
@@ -1,52 +0,0 @@
-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"
-
-       dsdata 
"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
-)
-
-// LastStats wraps a deliveryservice.LastStats object to be safe for multiple 
readers and one writer.
-type LastStats struct {
-       stats *dsdata.LastStats
-       m     *sync.RWMutex
-}
-
-// NewLastStats returns a wrapped a deliveryservice.LastStats object safe for 
multiple readers and one writer.
-func NewLastStats() LastStats {
-       s := dsdata.NewLastStats()
-       return LastStats{m: &sync.RWMutex{}, stats: &s}
-}
-
-// Get returns the last KBPS stats object. Callers MUST NOT modify the object. 
It is not threadsafe for writing. If the object must be modified, callers must 
call LastStats.Copy() and modify the copy.
-func (o *LastStats) Get() dsdata.LastStats {
-       o.m.RLock()
-       defer o.m.RUnlock()
-       return *o.stats
-}
-
-// Set sets the internal LastStats object. This MUST NOT be called by multiple 
goroutines.
-func (o *LastStats) Set(s dsdata.LastStats) {
-       o.m.Lock()
-       *o.stats = s
-       o.m.Unlock()
-}


Reply via email to