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

[24/29] incubator-trafficcontrol git commit: Update vendor going more thoroughly through deps recursively... some cleanup may be called for in a follow up PR

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go b/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
deleted file mode 100644
index d27c162..0000000
--- a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/client_test.go
+++ /dev/null
@@ -1,525 +0,0 @@
-package client
-
-import (
-	"encoding/json"
-	"net/http"
-	"net/http/httptest"
-	"reflect"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-)
-
-func TestUDPClient_Query(t *testing.T) {
-	config := UDPConfig{Addr: "localhost:8089"}
-	c, err := NewUDPClient(config)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-	defer c.Close()
-	query := Query{}
-	_, err = c.Query(query)
-	if err == nil {
-		t.Error("Querying UDP client should fail")
-	}
-}
-
-func TestUDPClient_Ping(t *testing.T) {
-	config := UDPConfig{Addr: "localhost:8089"}
-	c, err := NewUDPClient(config)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-	defer c.Close()
-
-	rtt, version, err := c.Ping(0)
-	if rtt != 0 || version != "" || err != nil {
-		t.Errorf("unexpected error.  expected (%v, '%v', %v), actual (%v, '%v', %v)", 0, "", nil, rtt, version, err)
-	}
-}
-
-func TestUDPClient_Write(t *testing.T) {
-	config := UDPConfig{Addr: "localhost:8089"}
-	c, err := NewUDPClient(config)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-	defer c.Close()
-
-	bp, err := NewBatchPoints(BatchPointsConfig{})
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-
-	fields := make(map[string]interface{})
-	fields["value"] = 1.0
-	pt, _ := NewPoint("cpu", make(map[string]string), fields)
-	bp.AddPoint(pt)
-
-	err = c.Write(bp)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-}
-
-func TestUDPClient_BadAddr(t *testing.T) {
-	config := UDPConfig{Addr: "foobar@wahoo"}
-	c, err := NewUDPClient(config)
-	if err == nil {
-		defer c.Close()
-		t.Error("Expected resolve error")
-	}
-}
-
-func TestUDPClient_Batches(t *testing.T) {
-	var logger writeLogger
-	var cl udpclient
-
-	cl.conn = &logger
-	cl.payloadSize = 20 // should allow for two points per batch
-
-	// expected point should look like this: "cpu a=1i"
-	fields := map[string]interface{}{"a": 1}
-
-	p, _ := NewPoint("cpu", nil, fields, time.Time{})
-
-	bp, _ := NewBatchPoints(BatchPointsConfig{})
-
-	for i := 0; i < 9; i++ {
-		bp.AddPoint(p)
-	}
-
-	if err := cl.Write(bp); err != nil {
-		t.Fatalf("Unexpected error during Write: %v", err)
-	}
-
-	if len(logger.writes) != 5 {
-		t.Errorf("Mismatched write count: got %v, exp %v", len(logger.writes), 5)
-	}
-}
-
-func TestUDPClient_Split(t *testing.T) {
-	var logger writeLogger
-	var cl udpclient
-
-	cl.conn = &logger
-	cl.payloadSize = 1 // force one field per point
-
-	fields := map[string]interface{}{"a": 1, "b": 2, "c": 3, "d": 4}
-
-	p, _ := NewPoint("cpu", nil, fields, time.Unix(1, 0))
-
-	bp, _ := NewBatchPoints(BatchPointsConfig{})
-
-	bp.AddPoint(p)
-
-	if err := cl.Write(bp); err != nil {
-		t.Fatalf("Unexpected error during Write: %v", err)
-	}
-
-	if len(logger.writes) != len(fields) {
-		t.Errorf("Mismatched write count: got %v, exp %v", len(logger.writes), len(fields))
-	}
-}
-
-type writeLogger struct {
-	writes [][]byte
-}
-
-func (w *writeLogger) Write(b []byte) (int, error) {
-	w.writes = append(w.writes, append([]byte(nil), b...))
-	return len(b), nil
-}
-
-func (w *writeLogger) Close() error { return nil }
-
-func TestClient_Query(t *testing.T) {
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		var data Response
-		w.WriteHeader(http.StatusOK)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	query := Query{}
-	_, err := c.Query(query)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-}
-
-func TestClient_BoundParameters(t *testing.T) {
-	var parameterString string
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		var data Response
-		r.ParseForm()
-		parameterString = r.FormValue("params")
-		w.WriteHeader(http.StatusOK)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	expectedParameters := map[string]interface{}{
-		"testStringParameter": "testStringValue",
-		"testNumberParameter": 12.3,
-	}
-
-	query := Query{
-		Parameters: expectedParameters,
-	}
-
-	_, err := c.Query(query)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-
-	var actualParameters map[string]interface{}
-
-	err = json.Unmarshal([]byte(parameterString), &actualParameters)
-	if err != nil {
-		t.Errorf("unexpected error. expected %v, actual %v", nil, err)
-	}
-
-	if !reflect.DeepEqual(expectedParameters, actualParameters) {
-		t.Errorf("unexpected parameters. expected %v, actual %v", expectedParameters, actualParameters)
-	}
-}
-
-func TestClient_BasicAuth(t *testing.T) {
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		u, p, ok := r.BasicAuth()
-
-		if !ok {
-			t.Errorf("basic auth error")
-		}
-		if u != "username" {
-			t.Errorf("unexpected username, expected %q, actual %q", "username", u)
-		}
-		if p != "password" {
-			t.Errorf("unexpected password, expected %q, actual %q", "password", p)
-		}
-		var data Response
-		w.WriteHeader(http.StatusOK)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL, Username: "username", Password: "password"}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	query := Query{}
-	_, err := c.Query(query)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-}
-
-func TestClient_Ping(t *testing.T) {
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		var data Response
-		w.WriteHeader(http.StatusNoContent)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	_, _, err := c.Ping(0)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-}
-
-func TestClient_Concurrent_Use(t *testing.T) {
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.WriteHeader(http.StatusOK)
-		w.Write([]byte(`{}`))
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	var wg sync.WaitGroup
-	wg.Add(3)
-	n := 1000
-
-	go func() {
-		defer wg.Done()
-		bp, err := NewBatchPoints(BatchPointsConfig{})
-		if err != nil {
-			t.Errorf("got error %v", err)
-		}
-
-		for i := 0; i < n; i++ {
-			if err = c.Write(bp); err != nil {
-				t.Fatalf("got error %v", err)
-			}
-		}
-	}()
-
-	go func() {
-		defer wg.Done()
-		var q Query
-		for i := 0; i < n; i++ {
-			if _, err := c.Query(q); err != nil {
-				t.Fatalf("got error %v", err)
-			}
-		}
-	}()
-
-	go func() {
-		defer wg.Done()
-		for i := 0; i < n; i++ {
-			c.Ping(time.Second)
-		}
-	}()
-	wg.Wait()
-}
-
-func TestClient_Write(t *testing.T) {
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		var data Response
-		w.WriteHeader(http.StatusNoContent)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	config := HTTPConfig{Addr: ts.URL}
-	c, _ := NewHTTPClient(config)
-	defer c.Close()
-
-	bp, err := NewBatchPoints(BatchPointsConfig{})
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-	err = c.Write(bp)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-}
-
-func TestClient_UserAgent(t *testing.T) {
-	receivedUserAgent := ""
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		receivedUserAgent = r.UserAgent()
-
-		var data Response
-		w.WriteHeader(http.StatusOK)
-		_ = json.NewEncoder(w).Encode(data)
-	}))
-	defer ts.Close()
-
-	_, err := http.Get(ts.URL)
-	if err != nil {
-		t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-	}
-
-	tests := []struct {
-		name      string
-		userAgent string
-		expected  string
-	}{
-		{
-			name:      "Empty user agent",
-			userAgent: "",
-			expected:  "InfluxDBClient",
-		},
-		{
-			name:      "Custom user agent",
-			userAgent: "Test Influx Client",
-			expected:  "Test Influx Client",
-		},
-	}
-
-	for _, test := range tests {
-
-		config := HTTPConfig{Addr: ts.URL, UserAgent: test.userAgent}
-		c, _ := NewHTTPClient(config)
-		defer c.Close()
-
-		receivedUserAgent = ""
-		query := Query{}
-		_, err = c.Query(query)
-		if err != nil {
-			t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-		}
-		if !strings.HasPrefix(receivedUserAgent, test.expected) {
-			t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
-		}
-
-		receivedUserAgent = ""
-		bp, _ := NewBatchPoints(BatchPointsConfig{})
-		err = c.Write(bp)
-		if err != nil {
-			t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-		}
-		if !strings.HasPrefix(receivedUserAgent, test.expected) {
-			t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
-		}
-
-		receivedUserAgent = ""
-		_, err := c.Query(query)
-		if err != nil {
-			t.Errorf("unexpected error.  expected %v, actual %v", nil, err)
-		}
-		if receivedUserAgent != test.expected {
-			t.Errorf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
-		}
-	}
-}
-
-func TestClient_PointString(t *testing.T) {
-	const shortForm = "2006-Jan-02"
-	time1, _ := time.Parse(shortForm, "2013-Feb-03")
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields, time1)
-
-	s := "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39 1359849600000000000"
-	if p.String() != s {
-		t.Errorf("Point String Error, got %s, expected %s", p.String(), s)
-	}
-
-	s = "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39 1359849600000"
-	if p.PrecisionString("ms") != s {
-		t.Errorf("Point String Error, got %s, expected %s",
-			p.PrecisionString("ms"), s)
-	}
-}
-
-func TestClient_PointWithoutTimeString(t *testing.T) {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields)
-
-	s := "cpu_usage,cpu=cpu-total idle=10.1,system=50.9,user=39"
-	if p.String() != s {
-		t.Errorf("Point String Error, got %s, expected %s", p.String(), s)
-	}
-
-	if p.PrecisionString("ms") != s {
-		t.Errorf("Point String Error, got %s, expected %s",
-			p.PrecisionString("ms"), s)
-	}
-}
-
-func TestClient_PointName(t *testing.T) {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields)
-
-	exp := "cpu_usage"
-	if p.Name() != exp {
-		t.Errorf("Error, got %s, expected %s",
-			p.Name(), exp)
-	}
-}
-
-func TestClient_PointTags(t *testing.T) {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields)
-
-	if !reflect.DeepEqual(tags, p.Tags()) {
-		t.Errorf("Error, got %v, expected %v",
-			p.Tags(), tags)
-	}
-}
-
-func TestClient_PointUnixNano(t *testing.T) {
-	const shortForm = "2006-Jan-02"
-	time1, _ := time.Parse(shortForm, "2013-Feb-03")
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields, time1)
-
-	exp := int64(1359849600000000000)
-	if p.UnixNano() != exp {
-		t.Errorf("Error, got %d, expected %d",
-			p.UnixNano(), exp)
-	}
-}
-
-func TestClient_PointFields(t *testing.T) {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
-	p, _ := NewPoint("cpu_usage", tags, fields)
-
-	pfields, err := p.Fields()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !reflect.DeepEqual(fields, pfields) {
-		t.Errorf("Error, got %v, expected %v",
-			pfields, fields)
-	}
-}
-
-func TestBatchPoints_PrecisionError(t *testing.T) {
-	_, err := NewBatchPoints(BatchPointsConfig{Precision: "foobar"})
-	if err == nil {
-		t.Errorf("Precision: foobar should have errored")
-	}
-
-	bp, _ := NewBatchPoints(BatchPointsConfig{Precision: "ns"})
-	err = bp.SetPrecision("foobar")
-	if err == nil {
-		t.Errorf("Precision: foobar should have errored")
-	}
-}
-
-func TestBatchPoints_SettersGetters(t *testing.T) {
-	bp, _ := NewBatchPoints(BatchPointsConfig{
-		Precision:        "ns",
-		Database:         "db",
-		RetentionPolicy:  "rp",
-		WriteConsistency: "wc",
-	})
-	if bp.Precision() != "ns" {
-		t.Errorf("Expected: %s, got %s", bp.Precision(), "ns")
-	}
-	if bp.Database() != "db" {
-		t.Errorf("Expected: %s, got %s", bp.Database(), "db")
-	}
-	if bp.RetentionPolicy() != "rp" {
-		t.Errorf("Expected: %s, got %s", bp.RetentionPolicy(), "rp")
-	}
-	if bp.WriteConsistency() != "wc" {
-		t.Errorf("Expected: %s, got %s", bp.WriteConsistency(), "wc")
-	}
-
-	bp.SetDatabase("db2")
-	bp.SetRetentionPolicy("rp2")
-	bp.SetWriteConsistency("wc2")
-	err := bp.SetPrecision("s")
-	if err != nil {
-		t.Errorf("Did not expect error: %s", err.Error())
-	}
-
-	if bp.Precision() != "s" {
-		t.Errorf("Expected: %s, got %s", bp.Precision(), "s")
-	}
-	if bp.Database() != "db2" {
-		t.Errorf("Expected: %s, got %s", bp.Database(), "db2")
-	}
-	if bp.RetentionPolicy() != "rp2" {
-		t.Errorf("Expected: %s, got %s", bp.RetentionPolicy(), "rp2")
-	}
-	if bp.WriteConsistency() != "wc2" {
-		t.Errorf("Expected: %s, got %s", bp.WriteConsistency(), "wc2")
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go b/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
deleted file mode 100644
index 68bb24b..0000000
--- a/traffic_stats/vendor/github.com/influxdata/influxdb/client/v2/example_test.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package client_test
-
-import (
-	"fmt"
-	"math/rand"
-	"os"
-	"time"
-
-	"github.com/influxdata/influxdb/client/v2"
-)
-
-// Create a new client
-func ExampleClient() {
-	// NOTE: this assumes you've setup a user and have setup shell env variables,
-	// namely INFLUX_USER/INFLUX_PWD. If not just omit Username/Password below.
-	_, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr:     "http://localhost:8086",
-		Username: os.Getenv("INFLUX_USER"),
-		Password: os.Getenv("INFLUX_PWD"),
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-}
-
-// Write a point using the UDP client
-func ExampleClient_uDP() {
-	// Make client
-	config := client.UDPConfig{Addr: "localhost:8089"}
-	c, err := client.NewUDPClient(config)
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-	defer c.Close()
-
-	// Create a new point batch
-	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
-		Precision: "s",
-	})
-
-	// Create a point and add to batch
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-	bp.AddPoint(pt)
-
-	// Write the batch
-	c.Write(bp)
-}
-
-// Ping the cluster using the HTTP client
-func ExampleClient_Ping() {
-	// Make client
-	c, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr: "http://localhost:8086",
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-	defer c.Close()
-
-	_, _, err = c.Ping(0)
-	if err != nil {
-		fmt.Println("Error pinging InfluxDB Cluster: ", err.Error())
-	}
-}
-
-// Write a point using the HTTP client
-func ExampleClient_write() {
-	// Make client
-	c, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr: "http://localhost:8086",
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-	defer c.Close()
-
-	// Create a new point batch
-	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
-		Database:  "BumbleBeeTuna",
-		Precision: "s",
-	})
-
-	// Create a point and add to batch
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-	bp.AddPoint(pt)
-
-	// Write the batch
-	c.Write(bp)
-}
-
-// Create a batch and add a point
-func ExampleBatchPoints() {
-	// Create a new point batch
-	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
-		Database:  "BumbleBeeTuna",
-		Precision: "s",
-	})
-
-	// Create a point and add to batch
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-	bp.AddPoint(pt)
-}
-
-// Using the BatchPoints setter functions
-func ExampleBatchPoints_setters() {
-	// Create a new point batch
-	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{})
-	bp.SetDatabase("BumbleBeeTuna")
-	bp.SetPrecision("ms")
-
-	// Create a point and add to batch
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-	bp.AddPoint(pt)
-}
-
-// Create a new point with a timestamp
-func ExamplePoint() {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now())
-	if err == nil {
-		fmt.Println("We created a point: ", pt.String())
-	}
-}
-
-// Create a new point without a timestamp
-func ExamplePoint_withoutTime() {
-	tags := map[string]string{"cpu": "cpu-total"}
-	fields := map[string]interface{}{
-		"idle":   10.1,
-		"system": 53.3,
-		"user":   46.6,
-	}
-	pt, err := client.NewPoint("cpu_usage", tags, fields)
-	if err == nil {
-		fmt.Println("We created a point w/o time: ", pt.String())
-	}
-}
-
-// Write 1000 points
-func ExampleClient_write1000() {
-	sampleSize := 1000
-
-	// Make client
-	c, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr: "http://localhost:8086",
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-	defer c.Close()
-
-	rand.Seed(42)
-
-	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
-		Database:  "systemstats",
-		Precision: "us",
-	})
-
-	for i := 0; i < sampleSize; i++ {
-		regions := []string{"us-west1", "us-west2", "us-west3", "us-east1"}
-		tags := map[string]string{
-			"cpu":    "cpu-total",
-			"host":   fmt.Sprintf("host%d", rand.Intn(1000)),
-			"region": regions[rand.Intn(len(regions))],
-		}
-
-		idle := rand.Float64() * 100.0
-		fields := map[string]interface{}{
-			"idle": idle,
-			"busy": 100.0 - idle,
-		}
-
-		pt, err := client.NewPoint(
-			"cpu_usage",
-			tags,
-			fields,
-			time.Now(),
-		)
-		if err != nil {
-			println("Error:", err.Error())
-			continue
-		}
-		bp.AddPoint(pt)
-	}
-
-	err = c.Write(bp)
-	if err != nil {
-		fmt.Println("Error: ", err.Error())
-	}
-}
-
-// Make a Query
-func ExampleClient_query() {
-	// Make client
-	c, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr: "http://localhost:8086",
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-	defer c.Close()
-
-	q := client.NewQuery("SELECT count(value) FROM shapes", "square_holes", "ns")
-	if response, err := c.Query(q); err == nil && response.Error() == nil {
-		fmt.Println(response.Results)
-	}
-}
-
-// Create a Database with a query
-func ExampleClient_createDatabase() {
-	// Make client
-	c, err := client.NewHTTPClient(client.HTTPConfig{
-		Addr: "http://localhost:8086",
-	})
-	if err != nil {
-		fmt.Println("Error creating InfluxDB Client: ", err.Error())
-	}
-	defer c.Close()
-
-	q := client.NewQuery("CREATE DATABASE telegraf", "", "")
-	if response, err := c.Query(q); err == nil && response.Error() == nil {
-		fmt.Println(response.Results)
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
new file mode 100644
index 0000000..2a3269b
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/consistency.go
@@ -0,0 +1,48 @@
+package models
+
+import (
+	"errors"
+	"strings"
+)
+
+// ConsistencyLevel represent a required replication criteria before a write can
+// be returned as successful.
+//
+// The consistency level is handled in open-source InfluxDB but only applicable to clusters.
+type ConsistencyLevel int
+
+const (
+	// ConsistencyLevelAny allows for hinted handoff, potentially no write happened yet.
+	ConsistencyLevelAny ConsistencyLevel = iota
+
+	// ConsistencyLevelOne requires at least one data node acknowledged a write.
+	ConsistencyLevelOne
+
+	// ConsistencyLevelQuorum requires a quorum of data nodes to acknowledge a write.
+	ConsistencyLevelQuorum
+
+	// ConsistencyLevelAll requires all data nodes to acknowledge a write.
+	ConsistencyLevelAll
+)
+
+var (
+	// ErrInvalidConsistencyLevel is returned when parsing the string version
+	// of a consistency level.
+	ErrInvalidConsistencyLevel = errors.New("invalid consistency level")
+)
+
+// ParseConsistencyLevel converts a consistency level string to the corresponding ConsistencyLevel const.
+func ParseConsistencyLevel(level string) (ConsistencyLevel, error) {
+	switch strings.ToLower(level) {
+	case "any":
+		return ConsistencyLevelAny, nil
+	case "one":
+		return ConsistencyLevelOne, nil
+	case "quorum":
+		return ConsistencyLevelQuorum, nil
+	case "all":
+		return ConsistencyLevelAll, nil
+	default:
+		return 0, ErrInvalidConsistencyLevel
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
new file mode 100644
index 0000000..1d8ae29
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_fnv.go
@@ -0,0 +1,32 @@
+package models
+
+// from stdlib hash/fnv/fnv.go
+const (
+	prime64  = 1099511628211
+	offset64 = 14695981039346656037
+)
+
+// InlineFNV64a is an alloc-free port of the standard library's fnv64a.
+// See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
+type InlineFNV64a uint64
+
+// NewInlineFNV64a returns a new instance of InlineFNV64a.
+func NewInlineFNV64a() InlineFNV64a {
+	return offset64
+}
+
+// Write adds data to the running hash.
+func (s *InlineFNV64a) Write(data []byte) (int, error) {
+	hash := uint64(*s)
+	for _, c := range data {
+		hash ^= uint64(c)
+		hash *= prime64
+	}
+	*s = InlineFNV64a(hash)
+	return len(data), nil
+}
+
+// Sum64 returns the uint64 of the current resulting hash.
+func (s *InlineFNV64a) Sum64() uint64 {
+	return uint64(*s)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
new file mode 100644
index 0000000..727ce35
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go
@@ -0,0 +1,38 @@
+package models
+
+import (
+	"reflect"
+	"strconv"
+	"unsafe"
+)
+
+// parseIntBytes is a zero-alloc wrapper around strconv.ParseInt.
+func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
+	s := unsafeBytesToString(b)
+	return strconv.ParseInt(s, base, bitSize)
+}
+
+// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
+func parseFloatBytes(b []byte, bitSize int) (float64, error) {
+	s := unsafeBytesToString(b)
+	return strconv.ParseFloat(s, bitSize)
+}
+
+// parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool.
+func parseBoolBytes(b []byte) (bool, error) {
+	return strconv.ParseBool(unsafeBytesToString(b))
+}
+
+// unsafeBytesToString converts a []byte to a string without a heap allocation.
+//
+// It is unsafe, and is intended to prepare input to short-lived functions
+// that require strings.
+func unsafeBytesToString(in []byte) string {
+	src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
+	dst := reflect.StringHeader{
+		Data: src.Data,
+		Len:  src.Len,
+	}
+	s := *(*string)(unsafe.Pointer(&dst))
+	return s
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
new file mode 100644
index 0000000..f415e01
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/points.go
@@ -0,0 +1,1997 @@
+// Package models implements basic objects used throughout the TICK stack.
+package models
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"math"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/influxdata/influxdb/pkg/escape"
+)
+
+var (
+	measurementEscapeCodes = map[byte][]byte{
+		',': []byte(`\,`),
+		' ': []byte(`\ `),
+	}
+
+	tagEscapeCodes = map[byte][]byte{
+		',': []byte(`\,`),
+		' ': []byte(`\ `),
+		'=': []byte(`\=`),
+	}
+
+	// ErrPointMustHaveAField is returned when operating on a point that does not have any fields.
+	ErrPointMustHaveAField = errors.New("point without fields is unsupported")
+
+	// ErrInvalidNumber is returned when a number is expected but not provided.
+	ErrInvalidNumber = errors.New("invalid number")
+
+	// ErrInvalidPoint is returned when a point cannot be parsed correctly.
+	ErrInvalidPoint = errors.New("point is invalid")
+)
+
+const (
+	// MaxKeyLength is the largest allowed size of the combined measurement and tag keys.
+	MaxKeyLength = 65535
+)
+
+// Point defines the values that will be written to the database.
+type Point interface {
+	// Name return the measurement name for the point.
+	Name() string
+
+	// SetName updates the measurement name for the point.
+	SetName(string)
+
+	// Tags returns the tag set for the point.
+	Tags() Tags
+
+	// AddTag adds or replaces a tag value for a point.
+	AddTag(key, value string)
+
+	// SetTags replaces the tags for the point.
+	SetTags(tags Tags)
+
+	// Fields returns the fields for the point.
+	Fields() (Fields, error)
+
+	// Time return the timestamp for the point.
+	Time() time.Time
+
+	// SetTime updates the timestamp for the point.
+	SetTime(t time.Time)
+
+	// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch.
+	UnixNano() int64
+
+	// HashID returns a non-cryptographic checksum of the point's key.
+	HashID() uint64
+
+	// Key returns the key (measurement joined with tags) of the point.
+	Key() []byte
+
+	// String returns a string representation of the point. If there is a
+	// timestamp associated with the point then it will be specified with the default
+	// precision of nanoseconds.
+	String() string
+
+	// MarshalBinary returns a binary representation of the point.
+	MarshalBinary() ([]byte, error)
+
+	// PrecisionString returns a string representation of the point. If there
+	// is a timestamp associated with the point then it will be specified in the
+	// given unit.
+	PrecisionString(precision string) string
+
+	// RoundedString returns a string representation of the point. If there
+	// is a timestamp associated with the point, then it will be rounded to the
+	// given duration.
+	RoundedString(d time.Duration) string
+
+	// Split will attempt to return multiple points with the same timestamp whose
+	// string representations are no longer than size. Points with a single field or
+	// a point without a timestamp may exceed the requested size.
+	Split(size int) []Point
+
+	// Round will round the timestamp of the point to the given duration.
+	Round(d time.Duration)
+
+	// StringSize returns the length of the string that would be returned by String().
+	StringSize() int
+
+	// AppendString appends the result of String() to the provided buffer and returns
+	// the result, potentially reducing string allocations.
+	AppendString(buf []byte) []byte
+
+	// FieldIterator retuns a FieldIterator that can be used to traverse the
+	// fields of a point without constructing the in-memory map.
+	FieldIterator() FieldIterator
+}
+
+// FieldType represents the type of a field.
+type FieldType int
+
+const (
+	// Integer indicates the field's type is integer.
+	Integer FieldType = iota
+
+	// Float indicates the field's type is float.
+	Float
+
+	// Boolean indicates the field's type is boolean.
+	Boolean
+
+	// String indicates the field's type is string.
+	String
+
+	// Empty is used to indicate that there is no field.
+	Empty
+)
+
+// FieldIterator provides a low-allocation interface to iterate through a point's fields.
+type FieldIterator interface {
+	// Next indicates whether there any fields remaining.
+	Next() bool
+
+	// FieldKey returns the key of the current field.
+	FieldKey() []byte
+
+	// Type returns the FieldType of the current field.
+	Type() FieldType
+
+	// StringValue returns the string value of the current field.
+	StringValue() string
+
+	// IntegerValue returns the integer value of the current field.
+	IntegerValue() (int64, error)
+
+	// BooleanValue returns the boolean value of the current field.
+	BooleanValue() (bool, error)
+
+	// FloatValue returns the float value of the current field.
+	FloatValue() (float64, error)
+
+	// Delete deletes the current field.
+	Delete()
+
+	// Reset resets the iterator to its initial state.
+	Reset()
+}
+
+// Points represents a sortable list of points by timestamp.
+type Points []Point
+
+// Len implements sort.Interface.
+func (a Points) Len() int { return len(a) }
+
+// Less implements sort.Interface.
+func (a Points) Less(i, j int) bool { return a[i].Time().Before(a[j].Time()) }
+
+// Swap implements sort.Interface.
+func (a Points) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// point is the default implementation of Point.
+type point struct {
+	time time.Time
+
+	// text encoding of measurement and tags
+	// key must always be stored sorted by tags, if the original line was not sorted,
+	// we need to resort it
+	key []byte
+
+	// text encoding of field data
+	fields []byte
+
+	// text encoding of timestamp
+	ts []byte
+
+	// cached version of parsed fields from data
+	cachedFields map[string]interface{}
+
+	// cached version of parsed name from key
+	cachedName string
+
+	// cached version of parsed tags
+	cachedTags Tags
+
+	it fieldIterator
+}
+
+const (
+	// the number of characters for the largest possible int64 (9223372036854775807)
+	maxInt64Digits = 19
+
+	// the number of characters for the smallest possible int64 (-9223372036854775808)
+	minInt64Digits = 20
+
+	// the number of characters required for the largest float64 before a range check
+	// would occur during parsing
+	maxFloat64Digits = 25
+
+	// the number of characters required for smallest float64 before a range check occur
+	// would occur during parsing
+	minFloat64Digits = 27
+)
+
+// ParsePoints returns a slice of Points from a text representation of a point
+// with each point separated by newlines.  If any points fail to parse, a non-nil error
+// will be returned in addition to the points that parsed successfully.
+func ParsePoints(buf []byte) ([]Point, error) {
+	return ParsePointsWithPrecision(buf, time.Now().UTC(), "n")
+}
+
+// ParsePointsString is identical to ParsePoints but accepts a string.
+func ParsePointsString(buf string) ([]Point, error) {
+	return ParsePoints([]byte(buf))
+}
+
+// ParseKey returns the measurement name and tags from a point.
+func ParseKey(buf []byte) (string, Tags, error) {
+	// Ignore the error because scanMeasurement returns "missing fields" which we ignore
+	// when just parsing a key
+	state, i, _ := scanMeasurement(buf, 0)
+
+	var tags Tags
+	if state == tagKeyState {
+		tags = parseTags(buf)
+		// scanMeasurement returns the location of the comma if there are tags, strip that off
+		return string(buf[:i-1]), tags, nil
+	}
+	return string(buf[:i]), tags, nil
+}
+
+// ParsePointsWithPrecision is similar to ParsePoints, but allows the
+// caller to provide a precision for time.
+func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) {
+	points := make([]Point, 0, bytes.Count(buf, []byte{'\n'})+1)
+	var (
+		pos    int
+		block  []byte
+		failed []string
+	)
+	for pos < len(buf) {
+		pos, block = scanLine(buf, pos)
+		pos++
+
+		if len(block) == 0 {
+			continue
+		}
+
+		// lines which start with '#' are comments
+		start := skipWhitespace(block, 0)
+
+		// If line is all whitespace, just skip it
+		if start >= len(block) {
+			continue
+		}
+
+		if block[start] == '#' {
+			continue
+		}
+
+		// strip the newline if one is present
+		if block[len(block)-1] == '\n' {
+			block = block[:len(block)-1]
+		}
+
+		pt, err := parsePoint(block[start:], defaultTime, precision)
+		if err != nil {
+			failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:len(block)]), err))
+		} else {
+			points = append(points, pt)
+		}
+
+	}
+	if len(failed) > 0 {
+		return points, fmt.Errorf("%s", strings.Join(failed, "\n"))
+	}
+	return points, nil
+
+}
+
+func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, error) {
+	// scan the first block which is measurement[,tag1=value1,tag2=value=2...]
+	pos, key, err := scanKey(buf, 0)
+	if err != nil {
+		return nil, err
+	}
+
+	// measurement name is required
+	if len(key) == 0 {
+		return nil, fmt.Errorf("missing measurement")
+	}
+
+	if len(key) > MaxKeyLength {
+		return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength)
+	}
+
+	// scan the second block is which is field1=value1[,field2=value2,...]
+	pos, fields, err := scanFields(buf, pos)
+	if err != nil {
+		return nil, err
+	}
+
+	// at least one field is required
+	if len(fields) == 0 {
+		return nil, fmt.Errorf("missing fields")
+	}
+
+	// scan the last block which is an optional integer timestamp
+	pos, ts, err := scanTime(buf, pos)
+	if err != nil {
+		return nil, err
+	}
+
+	pt := &point{
+		key:    key,
+		fields: fields,
+		ts:     ts,
+	}
+
+	if len(ts) == 0 {
+		pt.time = defaultTime
+		pt.SetPrecision(precision)
+	} else {
+		ts, err := parseIntBytes(ts, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+		pt.time, err = SafeCalcTime(ts, precision)
+		if err != nil {
+			return nil, err
+		}
+
+		// Determine if there are illegal non-whitespace characters after the
+		// timestamp block.
+		for pos < len(buf) {
+			if buf[pos] != ' ' {
+				return nil, ErrInvalidPoint
+			}
+			pos++
+		}
+	}
+	return pt, nil
+}
+
+// GetPrecisionMultiplier will return a multiplier for the precision specified.
+func GetPrecisionMultiplier(precision string) int64 {
+	d := time.Nanosecond
+	switch precision {
+	case "u":
+		d = time.Microsecond
+	case "ms":
+		d = time.Millisecond
+	case "s":
+		d = time.Second
+	case "m":
+		d = time.Minute
+	case "h":
+		d = time.Hour
+	}
+	return int64(d)
+}
+
+// scanKey scans buf starting at i for the measurement and tag portion of the point.
+// It returns the ending position and the byte slice of key within buf.  If there
+// are tags, they will be sorted if they are not already.
+func scanKey(buf []byte, i int) (int, []byte, error) {
+	start := skipWhitespace(buf, i)
+
+	i = start
+
+	// Determines whether the tags are sort, assume they are
+	sorted := true
+
+	// indices holds the indexes within buf of the start of each tag.  For example,
+	// a buf of 'cpu,host=a,region=b,zone=c' would have indices slice of [4,11,20]
+	// which indicates that the first tag starts at buf[4], seconds at buf[11], and
+	// last at buf[20]
+	indices := make([]int, 100)
+
+	// tracks how many commas we've seen so we know how many values are indices.
+	// Since indices is an arbitrarily large slice,
+	// we need to know how many values in the buffer are in use.
+	commas := 0
+
+	// First scan the Point's measurement.
+	state, i, err := scanMeasurement(buf, i)
+	if err != nil {
+		return i, buf[start:i], err
+	}
+
+	// Optionally scan tags if needed.
+	if state == tagKeyState {
+		i, commas, indices, err = scanTags(buf, i, indices)
+		if err != nil {
+			return i, buf[start:i], err
+		}
+	}
+
+	// Now we know where the key region is within buf, and the location of tags, we
+	// need to determine if duplicate tags exist and if the tags are sorted. This iterates
+	// over the list comparing each tag in the sequence with each other.
+	for j := 0; j < commas-1; j++ {
+		// get the left and right tags
+		_, left := scanTo(buf[indices[j]:indices[j+1]-1], 0, '=')
+		_, right := scanTo(buf[indices[j+1]:indices[j+2]-1], 0, '=')
+
+		// If left is greater than right, the tags are not sorted. We do not have to
+		// continue because the short path no longer works.
+		// If the tags are equal, then there are duplicate tags, and we should abort.
+		// If the tags are not sorted, this pass may not find duplicate tags and we
+		// need to do a more exhaustive search later.
+		if cmp := bytes.Compare(left, right); cmp > 0 {
+			sorted = false
+			break
+		} else if cmp == 0 {
+			return i, buf[start:i], fmt.Errorf("duplicate tags")
+		}
+	}
+
+	// If the tags are not sorted, then sort them.  This sort is inline and
+	// uses the tag indices we created earlier.  The actual buffer is not sorted, the
+	// indices are using the buffer for value comparison.  After the indices are sorted,
+	// the buffer is reconstructed from the sorted indices.
+	if !sorted && commas > 0 {
+		// Get the measurement name for later
+		measurement := buf[start : indices[0]-1]
+
+		// Sort the indices
+		indices := indices[:commas]
+		insertionSort(0, commas, buf, indices)
+
+		// Create a new key using the measurement and sorted indices
+		b := make([]byte, len(buf[start:i]))
+		pos := copy(b, measurement)
+		for _, i := range indices {
+			b[pos] = ','
+			pos++
+			_, v := scanToSpaceOr(buf, i, ',')
+			pos += copy(b[pos:], v)
+		}
+
+		// Check again for duplicate tags now that the tags are sorted.
+		for j := 0; j < commas-1; j++ {
+			// get the left and right tags
+			_, left := scanTo(buf[indices[j]:], 0, '=')
+			_, right := scanTo(buf[indices[j+1]:], 0, '=')
+
+			// If the tags are equal, then there are duplicate tags, and we should abort.
+			// If the tags are not sorted, this pass may not find duplicate tags and we
+			// need to do a more exhaustive search later.
+			if bytes.Equal(left, right) {
+				return i, b, fmt.Errorf("duplicate tags")
+			}
+		}
+
+		return i, b, nil
+	}
+
+	return i, buf[start:i], nil
+}
+
+// The following constants allow us to specify which state to move to
+// next, when scanning sections of a Point.
+const (
+	tagKeyState = iota
+	tagValueState
+	fieldsState
+)
+
+// scanMeasurement examines the measurement part of a Point, returning
+// the next state to move to, and the current location in the buffer.
+func scanMeasurement(buf []byte, i int) (int, int, error) {
+	// Check first byte of measurement, anything except a comma is fine.
+	// It can't be a space, since whitespace is stripped prior to this
+	// function call.
+	if i >= len(buf) || buf[i] == ',' {
+		return -1, i, fmt.Errorf("missing measurement")
+	}
+
+	for {
+		i++
+		if i >= len(buf) {
+			// cpu
+			return -1, i, fmt.Errorf("missing fields")
+		}
+
+		if buf[i-1] == '\\' {
+			// Skip character (it's escaped).
+			continue
+		}
+
+		// Unescaped comma; move onto scanning the tags.
+		if buf[i] == ',' {
+			return tagKeyState, i + 1, nil
+		}
+
+		// Unescaped space; move onto scanning the fields.
+		if buf[i] == ' ' {
+			// cpu value=1.0
+			return fieldsState, i, nil
+		}
+	}
+}
+
+// scanTags examines all the tags in a Point, keeping track of and
+// returning the updated indices slice, number of commas and location
+// in buf where to start examining the Point fields.
+func scanTags(buf []byte, i int, indices []int) (int, int, []int, error) {
+	var (
+		err    error
+		commas int
+		state  = tagKeyState
+	)
+
+	for {
+		switch state {
+		case tagKeyState:
+			// Grow our indices slice if we have too many tags.
+			if commas >= len(indices) {
+				newIndics := make([]int, cap(indices)*2)
+				copy(newIndics, indices)
+				indices = newIndics
+			}
+			indices[commas] = i
+			commas++
+
+			i, err = scanTagsKey(buf, i)
+			state = tagValueState // tag value always follows a tag key
+		case tagValueState:
+			state, i, err = scanTagsValue(buf, i)
+		case fieldsState:
+			indices[commas] = i + 1
+			return i, commas, indices, nil
+		}
+
+		if err != nil {
+			return i, commas, indices, err
+		}
+	}
+}
+
+// scanTagsKey scans each character in a tag key.
+func scanTagsKey(buf []byte, i int) (int, error) {
+	// First character of the key.
+	if i >= len(buf) || buf[i] == ' ' || buf[i] == ',' || buf[i] == '=' {
+		// cpu,{'', ' ', ',', '='}
+		return i, fmt.Errorf("missing tag key")
+	}
+
+	// Examine each character in the tag key until we hit an unescaped
+	// equals (the tag value), or we hit an error (i.e., unescaped
+	// space or comma).
+	for {
+		i++
+
+		// Either we reached the end of the buffer or we hit an
+		// unescaped comma or space.
+		if i >= len(buf) ||
+			((buf[i] == ' ' || buf[i] == ',') && buf[i-1] != '\\') {
+			// cpu,tag{'', ' ', ','}
+			return i, fmt.Errorf("missing tag value")
+		}
+
+		if buf[i] == '=' && buf[i-1] != '\\' {
+			// cpu,tag=
+			return i + 1, nil
+		}
+	}
+}
+
+// scanTagsValue scans each character in a tag value.
+func scanTagsValue(buf []byte, i int) (int, int, error) {
+	// Tag value cannot be empty.
+	if i >= len(buf) || buf[i] == ',' || buf[i] == ' ' {
+		// cpu,tag={',', ' '}
+		return -1, i, fmt.Errorf("missing tag value")
+	}
+
+	// Examine each character in the tag value until we hit an unescaped
+	// comma (move onto next tag key), an unescaped space (move onto
+	// fields), or we error out.
+	for {
+		i++
+		if i >= len(buf) {
+			// cpu,tag=value
+			return -1, i, fmt.Errorf("missing fields")
+		}
+
+		// An unescaped equals sign is an invalid tag value.
+		if buf[i] == '=' && buf[i-1] != '\\' {
+			// cpu,tag={'=', 'fo=o'}
+			return -1, i, fmt.Errorf("invalid tag format")
+		}
+
+		if buf[i] == ',' && buf[i-1] != '\\' {
+			// cpu,tag=foo,
+			return tagKeyState, i + 1, nil
+		}
+
+		// cpu,tag=foo value=1.0
+		// cpu, tag=foo\= value=1.0
+		if buf[i] == ' ' && buf[i-1] != '\\' {
+			return fieldsState, i, nil
+		}
+	}
+}
+
+func insertionSort(l, r int, buf []byte, indices []int) {
+	for i := l + 1; i < r; i++ {
+		for j := i; j > l && less(buf, indices, j, j-1); j-- {
+			indices[j], indices[j-1] = indices[j-1], indices[j]
+		}
+	}
+}
+
+func less(buf []byte, indices []int, i, j int) bool {
+	// This grabs the tag names for i & j, it ignores the values
+	_, a := scanTo(buf, indices[i], '=')
+	_, b := scanTo(buf, indices[j], '=')
+	return bytes.Compare(a, b) < 0
+}
+
+// scanFields scans buf, starting at i for the fields section of a point.  It returns
+// the ending position and the byte slice of the fields within buf.
+func scanFields(buf []byte, i int) (int, []byte, error) {
+	start := skipWhitespace(buf, i)
+	i = start
+	quoted := false
+
+	// tracks how many '=' we've seen
+	equals := 0
+
+	// tracks how many commas we've seen
+	commas := 0
+
+	for {
+		// reached the end of buf?
+		if i >= len(buf) {
+			break
+		}
+
+		// escaped characters?
+		if buf[i] == '\\' && i+1 < len(buf) {
+			i += 2
+			continue
+		}
+
+		// If the value is quoted, scan until we get to the end quote
+		// Only quote values in the field value since quotes are not significant
+		// in the field key
+		if buf[i] == '"' && equals > commas {
+			quoted = !quoted
+			i++
+			continue
+		}
+
+		// If we see an =, ensure that there is at least on char before and after it
+		if buf[i] == '=' && !quoted {
+			equals++
+
+			// check for "... =123" but allow "a\ =123"
+			if buf[i-1] == ' ' && buf[i-2] != '\\' {
+				return i, buf[start:i], fmt.Errorf("missing field key")
+			}
+
+			// check for "...a=123,=456" but allow "a=123,a\,=456"
+			if buf[i-1] == ',' && buf[i-2] != '\\' {
+				return i, buf[start:i], fmt.Errorf("missing field key")
+			}
+
+			// check for "... value="
+			if i+1 >= len(buf) {
+				return i, buf[start:i], fmt.Errorf("missing field value")
+			}
+
+			// check for "... value=,value2=..."
+			if buf[i+1] == ',' || buf[i+1] == ' ' {
+				return i, buf[start:i], fmt.Errorf("missing field value")
+			}
+
+			if isNumeric(buf[i+1]) || buf[i+1] == '-' || buf[i+1] == 'N' || buf[i+1] == 'n' {
+				var err error
+				i, err = scanNumber(buf, i+1)
+				if err != nil {
+					return i, buf[start:i], err
+				}
+				continue
+			}
+			// If next byte is not a double-quote, the value must be a boolean
+			if buf[i+1] != '"' {
+				var err error
+				i, _, err = scanBoolean(buf, i+1)
+				if err != nil {
+					return i, buf[start:i], err
+				}
+				continue
+			}
+		}
+
+		if buf[i] == ',' && !quoted {
+			commas++
+		}
+
+		// reached end of block?
+		if buf[i] == ' ' && !quoted {
+			break
+		}
+		i++
+	}
+
+	if quoted {
+		return i, buf[start:i], fmt.Errorf("unbalanced quotes")
+	}
+
+	// check that all field sections had key and values (e.g. prevent "a=1,b"
+	if equals == 0 || commas != equals-1 {
+		return i, buf[start:i], fmt.Errorf("invalid field format")
+	}
+
+	return i, buf[start:i], nil
+}
+
+// scanTime scans buf, starting at i for the time section of a point. It
+// returns the ending position and the byte slice of the timestamp within buf
+// and and error if the timestamp is not in the correct numeric format.
+func scanTime(buf []byte, i int) (int, []byte, error) {
+	start := skipWhitespace(buf, i)
+	i = start
+
+	for {
+		// reached the end of buf?
+		if i >= len(buf) {
+			break
+		}
+
+		// Reached end of block or trailing whitespace?
+		if buf[i] == '\n' || buf[i] == ' ' {
+			break
+		}
+
+		// Handle negative timestamps
+		if i == start && buf[i] == '-' {
+			i++
+			continue
+		}
+
+		// Timestamps should be integers, make sure they are so we don't need
+		// to actually  parse the timestamp until needed.
+		if buf[i] < '0' || buf[i] > '9' {
+			return i, buf[start:i], fmt.Errorf("bad timestamp")
+		}
+		i++
+	}
+	return i, buf[start:i], nil
+}
+
+func isNumeric(b byte) bool {
+	return (b >= '0' && b <= '9') || b == '.'
+}
+
+// scanNumber returns the end position within buf, start at i after
+// scanning over buf for an integer, or float.  It returns an
+// error if a invalid number is scanned.
+func scanNumber(buf []byte, i int) (int, error) {
+	start := i
+	var isInt bool
+
+	// Is negative number?
+	if i < len(buf) && buf[i] == '-' {
+		i++
+		// There must be more characters now, as just '-' is illegal.
+		if i == len(buf) {
+			return i, ErrInvalidNumber
+		}
+	}
+
+	// how many decimal points we've see
+	decimal := false
+
+	// indicates the number is float in scientific notation
+	scientific := false
+
+	for {
+		if i >= len(buf) {
+			break
+		}
+
+		if buf[i] == ',' || buf[i] == ' ' {
+			break
+		}
+
+		if buf[i] == 'i' && i > start && !isInt {
+			isInt = true
+			i++
+			continue
+		}
+
+		if buf[i] == '.' {
+			// Can't have more than 1 decimal (e.g. 1.1.1 should fail)
+			if decimal {
+				return i, ErrInvalidNumber
+			}
+			decimal = true
+		}
+
+		// `e` is valid for floats but not as the first char
+		if i > start && (buf[i] == 'e' || buf[i] == 'E') {
+			scientific = true
+			i++
+			continue
+		}
+
+		// + and - are only valid at this point if they follow an e (scientific notation)
+		if (buf[i] == '+' || buf[i] == '-') && (buf[i-1] == 'e' || buf[i-1] == 'E') {
+			i++
+			continue
+		}
+
+		// NaN is an unsupported value
+		if i+2 < len(buf) && (buf[i] == 'N' || buf[i] == 'n') {
+			return i, ErrInvalidNumber
+		}
+
+		if !isNumeric(buf[i]) {
+			return i, ErrInvalidNumber
+		}
+		i++
+	}
+
+	if isInt && (decimal || scientific) {
+		return i, ErrInvalidNumber
+	}
+
+	numericDigits := i - start
+	if isInt {
+		numericDigits--
+	}
+	if decimal {
+		numericDigits--
+	}
+	if buf[start] == '-' {
+		numericDigits--
+	}
+
+	if numericDigits == 0 {
+		return i, ErrInvalidNumber
+	}
+
+	// It's more common that numbers will be within min/max range for their type but we need to prevent
+	// out or range numbers from being parsed successfully.  This uses some simple heuristics to decide
+	// if we should parse the number to the actual type.  It does not do it all the time because it incurs
+	// extra allocations and we end up converting the type again when writing points to disk.
+	if isInt {
+		// Make sure the last char is an 'i' for integers (e.g. 9i10 is not valid)
+		if buf[i-1] != 'i' {
+			return i, ErrInvalidNumber
+		}
+		// Parse the int to check bounds the number of digits could be larger than the max range
+		// We subtract 1 from the index to remove the `i` from our tests
+		if len(buf[start:i-1]) >= maxInt64Digits || len(buf[start:i-1]) >= minInt64Digits {
+			if _, err := parseIntBytes(buf[start:i-1], 10, 64); err != nil {
+				return i, fmt.Errorf("unable to parse integer %s: %s", buf[start:i-1], err)
+			}
+		}
+	} else {
+		// Parse the float to check bounds if it's scientific or the number of digits could be larger than the max range
+		if scientific || len(buf[start:i]) >= maxFloat64Digits || len(buf[start:i]) >= minFloat64Digits {
+			if _, err := parseFloatBytes(buf[start:i], 10); err != nil {
+				return i, fmt.Errorf("invalid float")
+			}
+		}
+	}
+
+	return i, nil
+}
+
+// scanBoolean returns the end position within buf, start at i after
+// scanning over buf for boolean. Valid values for a boolean are
+// t, T, true, TRUE, f, F, false, FALSE.  It returns an error if a invalid boolean
+// is scanned.
+func scanBoolean(buf []byte, i int) (int, []byte, error) {
+	start := i
+
+	if i < len(buf) && (buf[i] != 't' && buf[i] != 'f' && buf[i] != 'T' && buf[i] != 'F') {
+		return i, buf[start:i], fmt.Errorf("invalid boolean")
+	}
+
+	i++
+	for {
+		if i >= len(buf) {
+			break
+		}
+
+		if buf[i] == ',' || buf[i] == ' ' {
+			break
+		}
+		i++
+	}
+
+	// Single char bool (t, T, f, F) is ok
+	if i-start == 1 {
+		return i, buf[start:i], nil
+	}
+
+	// length must be 4 for true or TRUE
+	if (buf[start] == 't' || buf[start] == 'T') && i-start != 4 {
+		return i, buf[start:i], fmt.Errorf("invalid boolean")
+	}
+
+	// length must be 5 for false or FALSE
+	if (buf[start] == 'f' || buf[start] == 'F') && i-start != 5 {
+		return i, buf[start:i], fmt.Errorf("invalid boolean")
+	}
+
+	// Otherwise
+	valid := false
+	switch buf[start] {
+	case 't':
+		valid = bytes.Equal(buf[start:i], []byte("true"))
+	case 'f':
+		valid = bytes.Equal(buf[start:i], []byte("false"))
+	case 'T':
+		valid = bytes.Equal(buf[start:i], []byte("TRUE")) || bytes.Equal(buf[start:i], []byte("True"))
+	case 'F':
+		valid = bytes.Equal(buf[start:i], []byte("FALSE")) || bytes.Equal(buf[start:i], []byte("False"))
+	}
+
+	if !valid {
+		return i, buf[start:i], fmt.Errorf("invalid boolean")
+	}
+
+	return i, buf[start:i], nil
+
+}
+
+// skipWhitespace returns the end position within buf, starting at i after
+// scanning over spaces in tags.
+func skipWhitespace(buf []byte, i int) int {
+	for i < len(buf) {
+		if buf[i] != ' ' && buf[i] != '\t' && buf[i] != 0 {
+			break
+		}
+		i++
+	}
+	return i
+}
+
+// scanLine returns the end position in buf and the next line found within
+// buf.
+func scanLine(buf []byte, i int) (int, []byte) {
+	start := i
+	quoted := false
+	fields := false
+
+	// tracks how many '=' and commas we've seen
+	// this duplicates some of the functionality in scanFields
+	equals := 0
+	commas := 0
+	for {
+		// reached the end of buf?
+		if i >= len(buf) {
+			break
+		}
+
+		// skip past escaped characters
+		if buf[i] == '\\' {
+			i += 2
+			continue
+		}
+
+		if buf[i] == ' ' {
+			fields = true
+		}
+
+		// If we see a double quote, makes sure it is not escaped
+		if fields {
+			if !quoted && buf[i] == '=' {
+				i++
+				equals++
+				continue
+			} else if !quoted && buf[i] == ',' {
+				i++
+				commas++
+				continue
+			} else if buf[i] == '"' && equals > commas {
+				i++
+				quoted = !quoted
+				continue
+			}
+		}
+
+		if buf[i] == '\n' && !quoted {
+			break
+		}
+
+		i++
+	}
+
+	return i, buf[start:i]
+}
+
+// scanTo returns the end position in buf and the next consecutive block
+// of bytes, starting from i and ending with stop byte, where stop byte
+// has not been escaped.
+//
+// If there are leading spaces, they are skipped.
+func scanTo(buf []byte, i int, stop byte) (int, []byte) {
+	start := i
+	for {
+		// reached the end of buf?
+		if i >= len(buf) {
+			break
+		}
+
+		// Reached unescaped stop value?
+		if buf[i] == stop && (i == 0 || buf[i-1] != '\\') {
+			break
+		}
+		i++
+	}
+
+	return i, buf[start:i]
+}
+
+// scanTo returns the end position in buf and the next consecutive block
+// of bytes, starting from i and ending with stop byte.  If there are leading
+// spaces, they are skipped.
+func scanToSpaceOr(buf []byte, i int, stop byte) (int, []byte) {
+	start := i
+	if buf[i] == stop || buf[i] == ' ' {
+		return i, buf[start:i]
+	}
+
+	for {
+		i++
+		if buf[i-1] == '\\' {
+			continue
+		}
+
+		// reached the end of buf?
+		if i >= len(buf) {
+			return i, buf[start:i]
+		}
+
+		// reached end of block?
+		if buf[i] == stop || buf[i] == ' ' {
+			return i, buf[start:i]
+		}
+	}
+}
+
+func scanTagValue(buf []byte, i int) (int, []byte) {
+	start := i
+	for {
+		if i >= len(buf) {
+			break
+		}
+
+		if buf[i] == ',' && buf[i-1] != '\\' {
+			break
+		}
+		i++
+	}
+	if i > len(buf) {
+		return i, nil
+	}
+	return i, buf[start:i]
+}
+
+func scanFieldValue(buf []byte, i int) (int, []byte) {
+	start := i
+	quoted := false
+	for i < len(buf) {
+		// Only escape char for a field value is a double-quote and backslash
+		if buf[i] == '\\' && i+1 < len(buf) && (buf[i+1] == '"' || buf[i+1] == '\\') {
+			i += 2
+			continue
+		}
+
+		// Quoted value? (e.g. string)
+		if buf[i] == '"' {
+			i++
+			quoted = !quoted
+			continue
+		}
+
+		if buf[i] == ',' && !quoted {
+			break
+		}
+		i++
+	}
+	return i, buf[start:i]
+}
+
+func escapeMeasurement(in []byte) []byte {
+	for b, esc := range measurementEscapeCodes {
+		in = bytes.Replace(in, []byte{b}, esc, -1)
+	}
+	return in
+}
+
+func unescapeMeasurement(in []byte) []byte {
+	for b, esc := range measurementEscapeCodes {
+		in = bytes.Replace(in, esc, []byte{b}, -1)
+	}
+	return in
+}
+
+func escapeTag(in []byte) []byte {
+	for b, esc := range tagEscapeCodes {
+		if bytes.IndexByte(in, b) != -1 {
+			in = bytes.Replace(in, []byte{b}, esc, -1)
+		}
+	}
+	return in
+}
+
+func unescapeTag(in []byte) []byte {
+	if bytes.IndexByte(in, '\\') == -1 {
+		return in
+	}
+
+	for b, esc := range tagEscapeCodes {
+		if bytes.IndexByte(in, b) != -1 {
+			in = bytes.Replace(in, esc, []byte{b}, -1)
+		}
+	}
+	return in
+}
+
+// escapeStringFieldReplacer replaces double quotes and backslashes
+// with the same character preceded by a backslash.
+// As of Go 1.7 this benchmarked better in allocations and CPU time
+// compared to iterating through a string byte-by-byte and appending to a new byte slice,
+// calling strings.Replace twice, and better than (*Regex).ReplaceAllString.
+var escapeStringFieldReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
+
+// EscapeStringField returns a copy of in with any double quotes or
+// backslashes with escaped values.
+func EscapeStringField(in string) string {
+	return escapeStringFieldReplacer.Replace(in)
+}
+
+// unescapeStringField returns a copy of in with any escaped double-quotes
+// or backslashes unescaped.
+func unescapeStringField(in string) string {
+	if strings.IndexByte(in, '\\') == -1 {
+		return in
+	}
+
+	var out []byte
+	i := 0
+	for {
+		if i >= len(in) {
+			break
+		}
+		// unescape backslashes
+		if in[i] == '\\' && i+1 < len(in) && in[i+1] == '\\' {
+			out = append(out, '\\')
+			i += 2
+			continue
+		}
+		// unescape double-quotes
+		if in[i] == '\\' && i+1 < len(in) && in[i+1] == '"' {
+			out = append(out, '"')
+			i += 2
+			continue
+		}
+		out = append(out, in[i])
+		i++
+
+	}
+	return string(out)
+}
+
+// NewPoint returns a new point with the given measurement name, tags, fields and timestamp.  If
+// an unsupported field value (NaN) or out of range time is passed, this function returns an error.
+func NewPoint(name string, tags Tags, fields Fields, t time.Time) (Point, error) {
+	key, err := pointKey(name, tags, fields, t)
+	if err != nil {
+		return nil, err
+	}
+
+	return &point{
+		key:    key,
+		time:   t,
+		fields: fields.MarshalBinary(),
+	}, nil
+}
+
+// pointKey checks some basic requirements for valid points, and returns the
+// key, along with an possible error.
+func pointKey(measurement string, tags Tags, fields Fields, t time.Time) ([]byte, error) {
+	if len(fields) == 0 {
+		return nil, ErrPointMustHaveAField
+	}
+
+	if !t.IsZero() {
+		if err := CheckTime(t); err != nil {
+			return nil, err
+		}
+	}
+
+	for key, value := range fields {
+		switch value := value.(type) {
+		case float64:
+			// Ensure the caller validates and handles invalid field values
+			if math.IsNaN(value) {
+				return nil, fmt.Errorf("NaN is an unsupported value for field %s", key)
+			}
+		case float32:
+			// Ensure the caller validates and handles invalid field values
+			if math.IsNaN(float64(value)) {
+				return nil, fmt.Errorf("NaN is an unsupported value for field %s", key)
+			}
+		}
+		if len(key) == 0 {
+			return nil, fmt.Errorf("all fields must have non-empty names")
+		}
+	}
+
+	key := MakeKey([]byte(measurement), tags)
+	if len(key) > MaxKeyLength {
+		return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength)
+	}
+
+	return key, nil
+}
+
+// NewPointFromBytes returns a new Point from a marshalled Point.
+func NewPointFromBytes(b []byte) (Point, error) {
+	p := &point{}
+	if err := p.UnmarshalBinary(b); err != nil {
+		return nil, err
+	}
+	fields, err := p.Fields()
+	if err != nil {
+		return nil, err
+	}
+	if len(fields) == 0 {
+		return nil, ErrPointMustHaveAField
+	}
+	return p, nil
+}
+
+// MustNewPoint returns a new point with the given measurement name, tags, fields and timestamp.  If
+// an unsupported field value (NaN) is passed, this function panics.
+func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point {
+	pt, err := NewPoint(name, tags, fields, time)
+	if err != nil {
+		panic(err.Error())
+	}
+	return pt
+}
+
+// Key returns the key (measurement joined with tags) of the point.
+func (p *point) Key() []byte {
+	return p.key
+}
+
+func (p *point) name() []byte {
+	_, name := scanTo(p.key, 0, ',')
+	return name
+}
+
+// Name return the measurement name for the point.
+func (p *point) Name() string {
+	if p.cachedName != "" {
+		return p.cachedName
+	}
+	p.cachedName = string(escape.Unescape(p.name()))
+	return p.cachedName
+}
+
+// SetName updates the measurement name for the point.
+func (p *point) SetName(name string) {
+	p.cachedName = ""
+	p.key = MakeKey([]byte(name), p.Tags())
+}
+
+// Time return the timestamp for the point.
+func (p *point) Time() time.Time {
+	return p.time
+}
+
+// SetTime updates the timestamp for the point.
+func (p *point) SetTime(t time.Time) {
+	p.time = t
+}
+
+// Round will round the timestamp of the point to the given duration.
+func (p *point) Round(d time.Duration) {
+	p.time = p.time.Round(d)
+}
+
+// Tags returns the tag set for the point.
+func (p *point) Tags() Tags {
+	if p.cachedTags != nil {
+		return p.cachedTags
+	}
+	p.cachedTags = parseTags(p.key)
+	return p.cachedTags
+}
+
+func parseTags(buf []byte) Tags {
+	if len(buf) == 0 {
+		return nil
+	}
+
+	pos, name := scanTo(buf, 0, ',')
+
+	// it's an empty key, so there are no tags
+	if len(name) == 0 {
+		return nil
+	}
+
+	tags := make(Tags, 0, bytes.Count(buf, []byte(",")))
+	hasEscape := bytes.IndexByte(buf, '\\') != -1
+
+	i := pos + 1
+	var key, value []byte
+	for {
+		if i >= len(buf) {
+			break
+		}
+		i, key = scanTo(buf, i, '=')
+		i, value = scanTagValue(buf, i+1)
+
+		if len(value) == 0 {
+			continue
+		}
+
+		if hasEscape {
+			tags = append(tags, Tag{Key: unescapeTag(key), Value: unescapeTag(value)})
+		} else {
+			tags = append(tags, Tag{Key: key, Value: value})
+		}
+
+		i++
+	}
+
+	return tags
+}
+
+// MakeKey creates a key for a set of tags.
+func MakeKey(name []byte, tags Tags) []byte {
+	// unescape the name and then re-escape it to avoid double escaping.
+	// The key should always be stored in escaped form.
+	return append(escapeMeasurement(unescapeMeasurement(name)), tags.HashKey()...)
+}
+
+// SetTags replaces the tags for the point.
+func (p *point) SetTags(tags Tags) {
+	p.key = MakeKey([]byte(p.Name()), tags)
+	p.cachedTags = tags
+}
+
+// AddTag adds or replaces a tag value for a point.
+func (p *point) AddTag(key, value string) {
+	tags := p.Tags()
+	tags = append(tags, Tag{Key: []byte(key), Value: []byte(value)})
+	sort.Sort(tags)
+	p.cachedTags = tags
+	p.key = MakeKey([]byte(p.Name()), tags)
+}
+
+// Fields returns the fields for the point.
+func (p *point) Fields() (Fields, error) {
+	if p.cachedFields != nil {
+		return p.cachedFields, nil
+	}
+	cf, err := p.unmarshalBinary()
+	if err != nil {
+		return nil, err
+	}
+	p.cachedFields = cf
+	return p.cachedFields, nil
+}
+
+// SetPrecision will round a time to the specified precision.
+func (p *point) SetPrecision(precision string) {
+	switch precision {
+	case "n":
+	case "u":
+		p.SetTime(p.Time().Truncate(time.Microsecond))
+	case "ms":
+		p.SetTime(p.Time().Truncate(time.Millisecond))
+	case "s":
+		p.SetTime(p.Time().Truncate(time.Second))
+	case "m":
+		p.SetTime(p.Time().Truncate(time.Minute))
+	case "h":
+		p.SetTime(p.Time().Truncate(time.Hour))
+	}
+}
+
+// String returns the string representation of the point.
+func (p *point) String() string {
+	if p.Time().IsZero() {
+		return string(p.Key()) + " " + string(p.fields)
+	}
+	return string(p.Key()) + " " + string(p.fields) + " " + strconv.FormatInt(p.UnixNano(), 10)
+}
+
+// AppendString appends the string representation of the point to buf.
+func (p *point) AppendString(buf []byte) []byte {
+	buf = append(buf, p.key...)
+	buf = append(buf, ' ')
+	buf = append(buf, p.fields...)
+
+	if !p.time.IsZero() {
+		buf = append(buf, ' ')
+		buf = strconv.AppendInt(buf, p.UnixNano(), 10)
+	}
+
+	return buf
+}
+
+// StringSize returns the length of the string that would be returned by String().
+func (p *point) StringSize() int {
+	size := len(p.key) + len(p.fields) + 1
+
+	if !p.time.IsZero() {
+		digits := 1 // even "0" has one digit
+		t := p.UnixNano()
+		if t < 0 {
+			// account for negative sign, then negate
+			digits++
+			t = -t
+		}
+		for t > 9 { // already accounted for one digit
+			digits++
+			t /= 10
+		}
+		size += digits + 1 // digits and a space
+	}
+
+	return size
+}
+
+// MarshalBinary returns a binary representation of the point.
+func (p *point) MarshalBinary() ([]byte, error) {
+	if len(p.fields) == 0 {
+		return nil, ErrPointMustHaveAField
+	}
+
+	tb, err := p.time.MarshalBinary()
+	if err != nil {
+		return nil, err
+	}
+
+	b := make([]byte, 8+len(p.key)+len(p.fields)+len(tb))
+	i := 0
+
+	binary.BigEndian.PutUint32(b[i:], uint32(len(p.key)))
+	i += 4
+
+	i += copy(b[i:], p.key)
+
+	binary.BigEndian.PutUint32(b[i:i+4], uint32(len(p.fields)))
+	i += 4
+
+	i += copy(b[i:], p.fields)
+
+	copy(b[i:], tb)
+	return b, nil
+}
+
+// UnmarshalBinary decodes a binary representation of the point into a point struct.
+func (p *point) UnmarshalBinary(b []byte) error {
+	var i int
+	keyLen := int(binary.BigEndian.Uint32(b[:4]))
+	i += int(4)
+
+	p.key = b[i : i+keyLen]
+	i += keyLen
+
+	fieldLen := int(binary.BigEndian.Uint32(b[i : i+4]))
+	i += int(4)
+
+	p.fields = b[i : i+fieldLen]
+	i += fieldLen
+
+	p.time = time.Now()
+	p.time.UnmarshalBinary(b[i:])
+	return nil
+}
+
+// PrecisionString returns a string representation of the point. If there
+// is a timestamp associated with the point then it will be specified in the
+// given unit.
+func (p *point) PrecisionString(precision string) string {
+	if p.Time().IsZero() {
+		return fmt.Sprintf("%s %s", p.Key(), string(p.fields))
+	}
+	return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields),
+		p.UnixNano()/GetPrecisionMultiplier(precision))
+}
+
+// RoundedString returns a string representation of the point. If there
+// is a timestamp associated with the point, then it will be rounded to the
+// given duration.
+func (p *point) RoundedString(d time.Duration) string {
+	if p.Time().IsZero() {
+		return fmt.Sprintf("%s %s", p.Key(), string(p.fields))
+	}
+	return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields),
+		p.time.Round(d).UnixNano())
+}
+
+func (p *point) unmarshalBinary() (Fields, error) {
+	iter := p.FieldIterator()
+	fields := make(Fields, 8)
+	for iter.Next() {
+		if len(iter.FieldKey()) == 0 {
+			continue
+		}
+		switch iter.Type() {
+		case Float:
+			v, err := iter.FloatValue()
+			if err != nil {
+				return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+			}
+			fields[string(iter.FieldKey())] = v
+		case Integer:
+			v, err := iter.IntegerValue()
+			if err != nil {
+				return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+			}
+			fields[string(iter.FieldKey())] = v
+		case String:
+			fields[string(iter.FieldKey())] = iter.StringValue()
+		case Boolean:
+			v, err := iter.BooleanValue()
+			if err != nil {
+				return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
+			}
+			fields[string(iter.FieldKey())] = v
+		}
+	}
+	return fields, nil
+}
+
+// HashID returns a non-cryptographic checksum of the point's key.
+func (p *point) HashID() uint64 {
+	h := NewInlineFNV64a()
+	h.Write(p.key)
+	sum := h.Sum64()
+	return sum
+}
+
+// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch.
+func (p *point) UnixNano() int64 {
+	return p.Time().UnixNano()
+}
+
+// Split will attempt to return multiple points with the same timestamp whose
+// string representations are no longer than size. Points with a single field or
+// a point without a timestamp may exceed the requested size.
+func (p *point) Split(size int) []Point {
+	if p.time.IsZero() || len(p.String()) <= size {
+		return []Point{p}
+	}
+
+	// key string, timestamp string, spaces
+	size -= len(p.key) + len(strconv.FormatInt(p.time.UnixNano(), 10)) + 2
+
+	var points []Point
+	var start, cur int
+
+	for cur < len(p.fields) {
+		end, _ := scanTo(p.fields, cur, '=')
+		end, _ = scanFieldValue(p.fields, end+1)
+
+		if cur > start && end-start > size {
+			points = append(points, &point{
+				key:    p.key,
+				time:   p.time,
+				fields: p.fields[start : cur-1],
+			})
+			start = cur
+		}
+
+		cur = end + 1
+	}
+
+	points = append(points, &point{
+		key:    p.key,
+		time:   p.time,
+		fields: p.fields[start:],
+	})
+
+	return points
+}
+
+// Tag represents a single key/value tag pair.
+type Tag struct {
+	Key   []byte
+	Value []byte
+}
+
+// Tags represents a sorted list of tags.
+type Tags []Tag
+
+// NewTags returns a new Tags from a map.
+func NewTags(m map[string]string) Tags {
+	if len(m) == 0 {
+		return nil
+	}
+	a := make(Tags, 0, len(m))
+	for k, v := range m {
+		a = append(a, Tag{Key: []byte(k), Value: []byte(v)})
+	}
+	sort.Sort(a)
+	return a
+}
+
+// Len implements sort.Interface.
+func (a Tags) Len() int { return len(a) }
+
+// Less implements sort.Interface.
+func (a Tags) Less(i, j int) bool { return bytes.Compare(a[i].Key, a[j].Key) == -1 }
+
+// Swap implements sort.Interface.
+func (a Tags) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// Get returns the value for a key.
+func (a Tags) Get(key []byte) []byte {
+	// OPTIMIZE: Use sort.Search if tagset is large.
+
+	for _, t := range a {
+		if bytes.Equal(t.Key, key) {
+			return t.Value
+		}
+	}
+	return nil
+}
+
+// GetString returns the string value for a string key.
+func (a Tags) GetString(key string) string {
+	return string(a.Get([]byte(key)))
+}
+
+// Set sets the value for a key.
+func (a *Tags) Set(key, value []byte) {
+	for _, t := range *a {
+		if bytes.Equal(t.Key, key) {
+			t.Value = value
+			return
+		}
+	}
+	*a = append(*a, Tag{Key: key, Value: value})
+	sort.Sort(*a)
+}
+
+// SetString sets the string value for a string key.
+func (a *Tags) SetString(key, value string) {
+	a.Set([]byte(key), []byte(value))
+}
+
+// Delete removes a tag by key.
+func (a *Tags) Delete(key []byte) {
+	for i, t := range *a {
+		if bytes.Equal(t.Key, key) {
+			copy((*a)[i:], (*a)[i+1:])
+			(*a)[len(*a)-1] = Tag{}
+			*a = (*a)[:len(*a)-1]
+			return
+		}
+	}
+}
+
+// Map returns a map representation of the tags.
+func (a Tags) Map() map[string]string {
+	m := make(map[string]string, len(a))
+	for _, t := range a {
+		m[string(t.Key)] = string(t.Value)
+	}
+	return m
+}
+
+// Merge merges the tags combining the two. If both define a tag with the
+// same key, the merged value overwrites the old value.
+// A new map is returned.
+func (a Tags) Merge(other map[string]string) Tags {
+	merged := make(map[string]string, len(a)+len(other))
+	for _, t := range a {
+		merged[string(t.Key)] = string(t.Value)
+	}
+	for k, v := range other {
+		merged[k] = v
+	}
+	return NewTags(merged)
+}
+
+// HashKey hashes all of a tag's keys.
+func (a Tags) HashKey() []byte {
+	// Empty maps marshal to empty bytes.
+	if len(a) == 0 {
+		return nil
+	}
+
+	escaped := make(Tags, 0, len(a))
+	for _, t := range a {
+		ek := escapeTag(t.Key)
+		ev := escapeTag(t.Value)
+
+		if len(ev) > 0 {
+			escaped = append(escaped, Tag{Key: ek, Value: ev})
+		}
+	}
+
+	// Extract keys and determine final size.
+	sz := len(escaped) + (len(escaped) * 2) // separators
+	keys := make([][]byte, len(escaped)+1)
+	for i, t := range escaped {
+		keys[i] = t.Key
+		sz += len(t.Key) + len(t.Value)
+	}
+	keys = keys[:len(escaped)]
+	sort.Sort(byteSlices(keys))
+
+	// Generate marshaled bytes.
+	b := make([]byte, sz)
+	buf := b
+	idx := 0
+	for i, k := range keys {
+		buf[idx] = ','
+		idx++
+		copy(buf[idx:idx+len(k)], k)
+		idx += len(k)
+		buf[idx] = '='
+		idx++
+		v := escaped[i].Value
+		copy(buf[idx:idx+len(v)], v)
+		idx += len(v)
+	}
+	return b[:idx]
+}
+
+// Fields represents a mapping between a Point's field names and their
+// values.
+type Fields map[string]interface{}
+
+func parseNumber(val []byte) (interface{}, error) {
+	if val[len(val)-1] == 'i' {
+		val = val[:len(val)-1]
+		return parseIntBytes(val, 10, 64)
+	}
+	for i := 0; i < len(val); i++ {
+		// If there is a decimal or an N (NaN), I (Inf), parse as float
+		if val[i] == '.' || val[i] == 'N' || val[i] == 'n' || val[i] == 'I' || val[i] == 'i' || val[i] == 'e' {
+			return parseFloatBytes(val, 64)
+		}
+		if val[i] < '0' && val[i] > '9' {
+			return string(val), nil
+		}
+	}
+	return parseFloatBytes(val, 64)
+}
+
+// FieldIterator retuns a FieldIterator that can be used to traverse the
+// fields of a point without constructing the in-memory map.
+func (p *point) FieldIterator() FieldIterator {
+	p.Reset()
+	return p
+}
+
+type fieldIterator struct {
+	start, end  int
+	key, keybuf []byte
+	valueBuf    []byte
+	fieldType   FieldType
+}
+
+// Next indicates whether there any fields remaining.
+func (p *point) Next() bool {
+	p.it.start = p.it.end
+	if p.it.start >= len(p.fields) {
+		return false
+	}
+
+	p.it.end, p.it.key = scanTo(p.fields, p.it.start, '=')
+	if escape.IsEscaped(p.it.key) {
+		p.it.keybuf = escape.AppendUnescaped(p.it.keybuf[:0], p.it.key)
+		p.it.key = p.it.keybuf
+	}
+
+	p.it.end, p.it.valueBuf = scanFieldValue(p.fields, p.it.end+1)
+	p.it.end++
+
+	if len(p.it.valueBuf) == 0 {
+		p.it.fieldType = Empty
+		return true
+	}
+
+	c := p.it.valueBuf[0]
+
+	if c == '"' {
+		p.it.fieldType = String
+		return true
+	}
+
+	if strings.IndexByte(`0123456789-.nNiI`, c) >= 0 {
+		if p.it.valueBuf[len(p.it.valueBuf)-1] == 'i' {
+			p.it.fieldType = Integer
+			p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1]
+		} else {
+			p.it.fieldType = Float
+		}
+		return true
+	}
+
+	// to keep the same behavior that currently exists, default to boolean
+	p.it.fieldType = Boolean
+	return true
+}
+
+// FieldKey returns the key of the current field.
+func (p *point) FieldKey() []byte {
+	return p.it.key
+}
+
+// Type returns the FieldType of the current field.
+func (p *point) Type() FieldType {
+	return p.it.fieldType
+}
+
+// StringValue returns the string value of the current field.
+func (p *point) StringValue() string {
+	return unescapeStringField(string(p.it.valueBuf[1 : len(p.it.valueBuf)-1]))
+}
+
+// IntegerValue returns the integer value of the current field.
+func (p *point) IntegerValue() (int64, error) {
+	n, err := parseIntBytes(p.it.valueBuf, 10, 64)
+	if err != nil {
+		return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err)
+	}
+	return n, nil
+}
+
+// BooleanValue returns the boolean value of the current field.
+func (p *point) BooleanValue() (bool, error) {
+	b, err := parseBoolBytes(p.it.valueBuf)
+	if err != nil {
+		return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err)
+	}
+	return b, nil
+}
+
+// FloatValue returns the float value of the current field.
+func (p *point) FloatValue() (float64, error) {
+	f, err := parseFloatBytes(p.it.valueBuf, 64)
+	if err != nil {
+		return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err)
+	}
+	return f, nil
+}
+
+// Delete deletes the current field.
+func (p *point) Delete() {
+	switch {
+	case p.it.end == p.it.start:
+	case p.it.end >= len(p.fields):
+		p.fields = p.fields[:p.it.start]
+	case p.it.start == 0:
+		p.fields = p.fields[p.it.end:]
+	default:
+		p.fields = append(p.fields[:p.it.start], p.fields[p.it.end:]...)
+	}
+
+	p.it.end = p.it.start
+	p.it.key = nil
+	p.it.valueBuf = nil
+	p.it.fieldType = Empty
+}
+
+// Reset resets the iterator to its initial state.
+func (p *point) Reset() {
+	p.it.fieldType = Empty
+	p.it.key = nil
+	p.it.valueBuf = nil
+	p.it.start = 0
+	p.it.end = 0
+}
+
+// MarshalBinary encodes all the fields to their proper type and returns the binary
+// represenation
+// NOTE: uint64 is specifically not supported due to potential overflow when we decode
+// again later to an int64
+// NOTE2: uint is accepted, and may be 64 bits, and is for some reason accepted...
+func (p Fields) MarshalBinary() []byte {
+	var b []byte
+	keys := make([]string, 0, len(p))
+
+	for k := range p {
+		keys = append(keys, k)
+	}
+
+	// Not really necessary, can probably be removed.
+	sort.Strings(keys)
+
+	for i, k := range keys {
+		if i > 0 {
+			b = append(b, ',')
+		}
+		b = appendField(b, k, p[k])
+	}
+
+	return b
+}
+
+func appendField(b []byte, k string, v interface{}) []byte {
+	b = append(b, []byte(escape.String(k))...)
+	b = append(b, '=')
+
+	// check popular types first
+	switch v := v.(type) {
+	case float64:
+		b = strconv.AppendFloat(b, v, 'f', -1, 64)
+	case int64:
+		b = strconv.AppendInt(b, v, 10)
+		b = append(b, 'i')
+	case string:
+		b = append(b, '"')
+		b = append(b, []byte(EscapeStringField(v))...)
+		b = append(b, '"')
+	case bool:
+		b = strconv.AppendBool(b, v)
+	case int32:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case int16:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case int8:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case int:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case uint32:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case uint16:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case uint8:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	// TODO: 'uint' should be considered just as "dangerous" as a uint64,
+	// perhaps the value should be checked and capped at MaxInt64? We could
+	// then include uint64 as an accepted value
+	case uint:
+		b = strconv.AppendInt(b, int64(v), 10)
+		b = append(b, 'i')
+	case float32:
+		b = strconv.AppendFloat(b, float64(v), 'f', -1, 32)
+	case []byte:
+		b = append(b, v...)
+	case nil:
+		// skip
+	default:
+		// Can't determine the type, so convert to string
+		b = append(b, '"')
+		b = append(b, []byte(EscapeStringField(fmt.Sprintf("%v", v)))...)
+		b = append(b, '"')
+
+	}
+
+	return b
+}
+
+type byteSlices [][]byte
+
+func (a byteSlices) Len() int           { return len(a) }
+func (a byteSlices) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) == -1 }
+func (a byteSlices) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
new file mode 100644
index 0000000..c087a48
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/rows.go
@@ -0,0 +1,62 @@
+package models
+
+import (
+	"sort"
+)
+
+// Row represents a single row returned from the execution of a statement.
+type Row struct {
+	Name    string            `json:"name,omitempty"`
+	Tags    map[string]string `json:"tags,omitempty"`
+	Columns []string          `json:"columns,omitempty"`
+	Values  [][]interface{}   `json:"values,omitempty"`
+	Partial bool              `json:"partial,omitempty"`
+}
+
+// SameSeries returns true if r contains values for the same series as o.
+func (r *Row) SameSeries(o *Row) bool {
+	return r.tagsHash() == o.tagsHash() && r.Name == o.Name
+}
+
+// tagsHash returns a hash of tag key/value pairs.
+func (r *Row) tagsHash() uint64 {
+	h := NewInlineFNV64a()
+	keys := r.tagsKeys()
+	for _, k := range keys {
+		h.Write([]byte(k))
+		h.Write([]byte(r.Tags[k]))
+	}
+	return h.Sum64()
+}
+
+// tagKeys returns a sorted list of tag keys.
+func (r *Row) tagsKeys() []string {
+	a := make([]string, 0, len(r.Tags))
+	for k := range r.Tags {
+		a = append(a, k)
+	}
+	sort.Strings(a)
+	return a
+}
+
+// Rows represents a collection of rows. Rows implements sort.Interface.
+type Rows []*Row
+
+// Len implements sort.Interface.
+func (p Rows) Len() int { return len(p) }
+
+// Less implements sort.Interface.
+func (p Rows) Less(i, j int) bool {
+	// Sort by name first.
+	if p[i].Name != p[j].Name {
+		return p[i].Name < p[j].Name
+	}
+
+	// Sort by tag set hash. Tags don't have a meaningful sort order so we
+	// just compute a hash and sort by that instead. This allows the tests
+	// to receive rows in a predictable order every time.
+	return p[i].tagsHash() < p[j].tagsHash()
+}
+
+// Swap implements sort.Interface.
+func (p Rows) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
new file mode 100644
index 0000000..553e9d0
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/statistic.go
@@ -0,0 +1,42 @@
+package models
+
+// Statistic is the representation of a statistic used by the monitoring service.
+type Statistic struct {
+	Name   string                 `json:"name"`
+	Tags   map[string]string      `json:"tags"`
+	Values map[string]interface{} `json:"values"`
+}
+
+// NewStatistic returns an initialized Statistic.
+func NewStatistic(name string) Statistic {
+	return Statistic{
+		Name:   name,
+		Tags:   make(map[string]string),
+		Values: make(map[string]interface{}),
+	}
+}
+
+// StatisticTags is a map that can be merged with others without causing
+// mutations to either map.
+type StatisticTags map[string]string
+
+// Merge creates a new map containing the merged contents of tags and t.
+// If both tags and the receiver map contain the same key, the value in tags
+// is used in the resulting map.
+//
+// Merge always returns a usable map.
+func (t StatisticTags) Merge(tags map[string]string) map[string]string {
+	// Add everything in tags to the result.
+	out := make(map[string]string, len(tags))
+	for k, v := range tags {
+		out[k] = v
+	}
+
+	// Only add values from t that don't appear in tags.
+	for k, v := range t {
+		if _, ok := tags[k]; !ok {
+			out[k] = v
+		}
+	}
+	return out
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go b/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
new file mode 100644
index 0000000..e98f2cb
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/models/time.go
@@ -0,0 +1,74 @@
+package models
+
+// Helper time methods since parsing time can easily overflow and we only support a
+// specific time range.
+
+import (
+	"fmt"
+	"math"
+	"time"
+)
+
+const (
+	// MinNanoTime is the minumum time that can be represented.
+	//
+	// 1677-09-21 00:12:43.145224194 +0000 UTC
+	//
+	// The two lowest minimum integers are used as sentinel values.  The
+	// minimum value needs to be used as a value lower than any other value for
+	// comparisons and another separate value is needed to act as a sentinel
+	// default value that is unusable by the user, but usable internally.
+	// Because these two values need to be used for a special purpose, we do
+	// not allow users to write points at these two times.
+	MinNanoTime = int64(math.MinInt64) + 2
+
+	// MaxNanoTime is the maximum time that can be represented.
+	//
+	// 2262-04-11 23:47:16.854775806 +0000 UTC
+	//
+	// The highest time represented by a nanosecond needs to be used for an
+	// exclusive range in the shard group, so the maximum time needs to be one
+	// less than the possible maximum number of nanoseconds representable by an
+	// int64 so that we don't lose a point at that one time.
+	MaxNanoTime = int64(math.MaxInt64) - 1
+)
+
+var (
+	minNanoTime = time.Unix(0, MinNanoTime).UTC()
+	maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
+
+	// ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
+	ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime)
+)
+
+// SafeCalcTime safely calculates the time given. Will return error if the time is outside the
+// supported range.
+func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
+	mult := GetPrecisionMultiplier(precision)
+	if t, ok := safeSignedMult(timestamp, mult); ok {
+		tme := time.Unix(0, t).UTC()
+		return tme, CheckTime(tme)
+	}
+
+	return time.Time{}, ErrTimeOutOfRange
+}
+
+// CheckTime checks that a time is within the safe range.
+func CheckTime(t time.Time) error {
+	if t.Before(minNanoTime) || t.After(maxNanoTime) {
+		return ErrTimeOutOfRange
+	}
+	return nil
+}
+
+// Perform the multiplication and check to make sure it didn't overflow.
+func safeSignedMult(a, b int64) (int64, bool) {
+	if a == 0 || b == 0 || a == 1 || b == 1 {
+		return a * b, true
+	}
+	if a == MinNanoTime || b == MaxNanoTime {
+		return 0, false
+	}
+	c := a * b
+	return c, c/b == a
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
new file mode 100644
index 0000000..f148d66
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go
@@ -0,0 +1,111 @@
+// Package escape contains utilities for escaping parts of InfluxQL
+// and InfluxDB line protocol.
+package escape
+
+import (
+	"bytes"
+	"strings"
+)
+
+// Codes is a map of bytes to be escaped.
+var Codes = map[byte][]byte{
+	',': []byte(`\,`),
+	'"': []byte(`\"`),
+	' ': []byte(`\ `),
+	'=': []byte(`\=`),
+}
+
+// Bytes escapes characters on the input slice, as defined by Codes.
+func Bytes(in []byte) []byte {
+	for b, esc := range Codes {
+		in = bytes.Replace(in, []byte{b}, esc, -1)
+	}
+	return in
+}
+
+const escapeChars = `," =`
+
+// IsEscaped returns whether b has any escaped characters,
+// i.e. whether b seems to have been processed by Bytes.
+func IsEscaped(b []byte) bool {
+	for len(b) > 0 {
+		i := bytes.IndexByte(b, '\\')
+		if i < 0 {
+			return false
+		}
+
+		if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 {
+			return true
+		}
+		b = b[i+1:]
+	}
+	return false
+}
+
+// AppendUnescaped appends the unescaped version of src to dst
+// and returns the resulting slice.
+func AppendUnescaped(dst, src []byte) []byte {
+	var pos int
+	for len(src) > 0 {
+		next := bytes.IndexByte(src[pos:], '\\')
+		if next < 0 || pos+next+1 >= len(src) {
+			return append(dst, src...)
+		}
+
+		if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 {
+			if pos+next > 0 {
+				dst = append(dst, src[:pos+next]...)
+			}
+			src = src[pos+next+1:]
+			pos = 0
+		} else {
+			pos += next + 1
+		}
+	}
+
+	return dst
+}
+
+// Unescape returns a new slice containing the unescaped version of in.
+func Unescape(in []byte) []byte {
+	if len(in) == 0 {
+		return nil
+	}
+
+	if bytes.IndexByte(in, '\\') == -1 {
+		return in
+	}
+
+	i := 0
+	inLen := len(in)
+	var out []byte
+
+	for {
+		if i >= inLen {
+			break
+		}
+		if in[i] == '\\' && i+1 < inLen {
+			switch in[i+1] {
+			case ',':
+				out = append(out, ',')
+				i += 2
+				continue
+			case '"':
+				out = append(out, '"')
+				i += 2
+				continue
+			case ' ':
+				out = append(out, ' ')
+				i += 2
+				continue
+			case '=':
+				out = append(out, '=')
+				i += 2
+				continue
+			}
+		}
+		out = append(out, in[i])
+		i += 1
+	}
+	return out
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
new file mode 100644
index 0000000..db98033
--- /dev/null
+++ b/traffic_stats/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go
@@ -0,0 +1,21 @@
+package escape
+
+import "strings"
+
+var (
+	escaper   = strings.NewReplacer(`,`, `\,`, `"`, `\"`, ` `, `\ `, `=`, `\=`)
+	unescaper = strings.NewReplacer(`\,`, `,`, `\"`, `"`, `\ `, ` `, `\=`, `=`)
+)
+
+// UnescapeString returns unescaped version of in.
+func UnescapeString(in string) string {
+	if strings.IndexByte(in, '\\') == -1 {
+		return in
+	}
+	return unescaper.Replace(in)
+}
+
+// String returns the escaped version of in.
+func String(in string) string {
+	return escaper.Replace(in)
+}