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:19 UTC

[23/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/jheitz200/test_helper/http.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/jheitz200/test_helper/http.go b/traffic_stats/vendor/github.com/jheitz200/test_helper/http.go
new file mode 100644
index 0000000..808414f
--- /dev/null
+++ b/traffic_stats/vendor/github.com/jheitz200/test_helper/http.go
@@ -0,0 +1,44 @@
+/*
+   Copyright 2015 Comcast Cable Communications Management, LLC
+
+   Licensed 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.
+*/
+
+package testHelper
+
+import (
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+)
+
+// ValidHTTPServer starts and returns a new test server.  Always
+// responds with a statusCode of 200 and the specified payload.
+func ValidHTTPServer(resp interface{}) *httptest.Server {
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusOK)
+		w.Header().Set("Content-Type", "application/json")
+		json.NewEncoder(w).Encode(resp)
+	}))
+	return server
+}
+
+// InvalidHTTPServer starts and returns a new test server.
+// Responds with the specified statusCode.
+func InvalidHTTPServer(statusCode int) *httptest.Server {
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(statusCode)
+		w.Header().Set("Content-Type", "application/json")
+	}))
+	return server
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/jheitz200/test_helper/test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/jheitz200/test_helper/test.go b/traffic_stats/vendor/github.com/jheitz200/test_helper/test.go
new file mode 100644
index 0000000..a314059
--- /dev/null
+++ b/traffic_stats/vendor/github.com/jheitz200/test_helper/test.go
@@ -0,0 +1,66 @@
+/*
+   Copyright 2015 Comcast Cable Communications Management, LLC
+
+   Licensed 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.
+*/
+
+package testHelper
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/cihub/seelog"
+)
+
+// Succeed is the Unicode codepoint for a check mark.
+const Succeed = "\u2713"
+
+// Failed is the Unicode codepoint for an X mark.
+const Failed = "\u2717"
+
+func init() {
+	// An example seelog.xml is located at conf/seelog.xml
+	// If you want to use this config - copy it to your project
+	seelogConfig := "conf/seelog.xml.test"
+	logger, err := seelog.LoggerFromConfigAsFile(seelogConfig)
+	if err != nil {
+		err := fmt.Errorf("FOO Error creating Logger from seelog file: %s", seelogConfig)
+		seelog.Error(err)
+	}
+	defer seelog.Flush()
+	seelog.ReplaceLogger(logger)
+}
+
+// Context is a summary of the test being run.
+func Context(t *testing.T, msg string, args ...interface{}) {
+	t.Log(fmt.Sprintf(msg, args...))
+}
+
+// Fatal contains details of a failed test and stops its execution.
+func Fatal(t *testing.T, msg string, args ...interface{}) {
+	m := fmt.Sprintf(msg, args...)
+	t.Fatal(fmt.Sprintf("\t %-80s", m), Failed)
+}
+
+// Error contails details of a failed test and continues execution.
+func Error(t *testing.T, msg string, args ...interface{}) {
+	m := fmt.Sprintf(msg, args...)
+	t.Error(fmt.Sprintf("\t %-80s", m), Failed)
+}
+
+// Success contains details of a successful test.
+func Success(t *testing.T, msg string, args ...interface{}) {
+	m := fmt.Sprintf(msg, args...)
+	t.Log(fmt.Sprintf("\t %-80s", m), Succeed)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/LICENSE
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/LICENSE b/traffic_stats/vendor/github.com/juju/go4/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/LICENSE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/.gitignore
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/.gitignore b/traffic_stats/vendor/github.com/juju/go4/lock/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/.gitignore
@@ -0,0 +1 @@
+*~

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock.go
new file mode 100644
index 0000000..a9fb802
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock.go
@@ -0,0 +1,186 @@
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+// Package lock is a file locking library.
+package lock
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"sync"
+)
+
+// Lock locks the given file, creating the file if necessary. If the
+// file already exists, it must have zero size or an error is returned.
+// The lock is an exclusive lock (a write lock), but locked files
+// should neither be read from nor written to. Such files should have
+// zero size and only exist to co-ordinate ownership across processes.
+//
+// A nil Closer is returned if an error occurred. Otherwise, close that
+// Closer to release the lock.
+//
+// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s
+// advisory locks.  In particular, closing any other file descriptor for the
+// same file will release the lock prematurely.
+//
+// Attempting to lock a file that is already locked by the current process
+// has undefined behavior.
+//
+// On other operating systems, lock will fallback to using the presence and
+// content of a file named name + '.lock' to implement locking behavior.
+func Lock(name string) (io.Closer, error) {
+	abs, err := filepath.Abs(name)
+	if err != nil {
+		return nil, err
+	}
+	lockmu.Lock()
+	defer lockmu.Unlock()
+	if locked[abs] {
+		return nil, fmt.Errorf("file %q already locked", abs)
+	}
+
+	c, err := lockFn(abs)
+	if err != nil {
+		return nil, fmt.Errorf("cannot acquire lock: %v", err)
+	}
+	locked[abs] = true
+	return c, nil
+}
+
+var lockFn = lockPortable
+
+// lockPortable is a portable version not using fcntl. Doesn't handle crashes as gracefully,
+// since it can leave stale lock files.
+func lockPortable(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		st := portableLockStatus(name)
+		switch st {
+		case statusLocked:
+			return nil, fmt.Errorf("file %q already locked", name)
+		case statusStale:
+			os.Remove(name)
+		case statusInvalid:
+			return nil, fmt.Errorf("can't Lock file %q: has invalid contents", name)
+		}
+	}
+	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create lock file %s %v", name, err)
+	}
+	if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil {
+		return nil, fmt.Errorf("cannot write owner pid: %v", err)
+	}
+	return &unlocker{
+		f:        f,
+		abs:      name,
+		portable: true,
+	}, nil
+}
+
+type lockStatus int
+
+const (
+	statusInvalid lockStatus = iota
+	statusLocked
+	statusUnlocked
+	statusStale
+)
+
+type pidLockMeta struct {
+	OwnerPID int
+}
+
+func portableLockStatus(path string) lockStatus {
+	f, err := os.Open(path)
+	if err != nil {
+		return statusUnlocked
+	}
+	defer f.Close()
+	var meta pidLockMeta
+	if json.NewDecoder(f).Decode(&meta) != nil {
+		return statusInvalid
+	}
+	if meta.OwnerPID == 0 {
+		return statusInvalid
+	}
+	p, err := os.FindProcess(meta.OwnerPID)
+	if err != nil {
+		// e.g. on Windows
+		return statusStale
+	}
+	// On unix, os.FindProcess always is true, so we have to send
+	// it a signal to see if it's alive.
+	if signalZero != nil {
+		if p.Signal(signalZero) != nil {
+			return statusStale
+		}
+	}
+	return statusLocked
+}
+
+var signalZero os.Signal // nil or set by lock_sigzero.go
+
+var (
+	lockmu sync.Mutex
+	locked = map[string]bool{} // abs path -> true
+)
+
+type unlocker struct {
+	portable bool
+	f        *os.File
+	abs      string
+	// once guards the close method call.
+	once sync.Once
+	// err holds the error returned by Close.
+	err error
+}
+
+func (u *unlocker) Close() error {
+	u.once.Do(u.close)
+	return u.err
+}
+
+func (u *unlocker) close() {
+	lockmu.Lock()
+	defer lockmu.Unlock()
+	delete(locked, u.abs)
+
+	if u.portable {
+		// In the portable lock implementation, it's
+		// important to close before removing because
+		// Windows won't allow us to remove an open
+		// file.
+		if err := u.f.Close(); err != nil {
+			u.err = err
+		}
+		if err := os.Remove(u.abs); err != nil {
+			// Note that if both Close and Remove fail,
+			// we care more about the latter than the former
+			// so we'll return that error.
+			u.err = err
+		}
+		return
+	}
+	// In other implementatioons, it's nice for us to clean up.
+	// If we do do this, though, it needs to be before the
+	// u.f.Close below.
+	os.Remove(u.abs)
+	u.err = u.f.Close()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_appengine.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_appengine.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_appengine.go
new file mode 100644
index 0000000..ab4cad6
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_appengine.go
@@ -0,0 +1,32 @@
+// +build appengine
+
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"errors"
+	"io"
+)
+
+func init() {
+	lockFn = lockAppEngine
+}
+
+func lockAppEngine(name string) (io.Closer, error) {
+	return nil, errors.New("Lock not available on App Engine")
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_darwin_amd64.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_darwin_amd64.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_darwin_amd64.go
new file mode 100644
index 0000000..35f5787
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_darwin_amd64.go
@@ -0,0 +1,67 @@
+// +build darwin,amd64
+// +build !appengine
+
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func init() {
+	lockFn = lockFcntl
+}
+
+func lockFcntl(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+	}
+
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, fmt.Errorf("Lock Create of %s failed: %v", name, err)
+	}
+
+	// This type matches C's "struct flock" defined in /usr/include/sys/fcntl.h.
+	// TODO: move this into the standard syscall package.
+	k := struct {
+		Start  uint64 // sizeof(off_t): 8
+		Len    uint64 // sizeof(off_t): 8
+		Pid    uint32 // sizeof(pid_t): 4
+		Type   uint16 // sizeof(short): 2
+		Whence uint16 // sizeof(short): 2
+	}{
+		Type:   syscall.F_WRLCK,
+		Whence: uint16(os.SEEK_SET),
+		Start:  0,
+		Len:    0, // 0 means to lock the entire file.
+		Pid:    uint32(os.Getpid()),
+	}
+
+	_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
+	if errno != 0 {
+		f.Close()
+		return nil, errno
+	}
+	return &unlocker{f: f, abs: name}, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_freebsd.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_freebsd.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_freebsd.go
new file mode 100644
index 0000000..ee2767a
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_freebsd.go
@@ -0,0 +1,66 @@
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func init() {
+	lockFn = lockFcntl
+}
+
+func lockFcntl(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+	}
+
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, err
+	}
+
+	// This type matches C's "struct flock" defined in /usr/include/fcntl.h.
+	// TODO: move this into the standard syscall package.
+	k := struct {
+		Start  int64 /* off_t starting offset */
+		Len    int64 /* off_t len = 0 means until end of file */
+		Pid    int32 /* pid_t lock owner */
+		Type   int16 /* short lock type: read/write, etc. */
+		Whence int16 /* short type of l_start */
+		Sysid  int32 /* int   remote system id or zero for local */
+	}{
+		Start:  0,
+		Len:    0, // 0 means to lock the entire file.
+		Pid:    int32(os.Getpid()),
+		Type:   syscall.F_WRLCK,
+		Whence: int16(os.SEEK_SET),
+		Sysid:  0,
+	}
+
+	_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
+	if errno != 0 {
+		f.Close()
+		return nil, errno
+	}
+	return &unlocker{f: f, abs: name}, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_amd64.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_amd64.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_amd64.go
new file mode 100644
index 0000000..08b3aae
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_amd64.go
@@ -0,0 +1,67 @@
+// +build linux,amd64
+// +build !appengine
+
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func init() {
+	lockFn = lockFcntl
+}
+
+func lockFcntl(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+	}
+
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, err
+	}
+
+	// This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h.
+	// TODO: move this into the standard syscall package.
+	k := struct {
+		Type   uint32
+		Whence uint32
+		Start  uint64
+		Len    uint64
+		Pid    uint32
+	}{
+		Type:   syscall.F_WRLCK,
+		Whence: uint32(os.SEEK_SET),
+		Start:  0,
+		Len:    0, // 0 means to lock the entire file.
+		Pid:    uint32(os.Getpid()),
+	}
+
+	_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
+	if errno != 0 {
+		f.Close()
+		return nil, errno
+	}
+	return &unlocker{f: f, abs: name}, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_arm.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_arm.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_arm.go
new file mode 100644
index 0000000..ebf87bd
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_linux_arm.go
@@ -0,0 +1,68 @@
+// +build linux,arm
+// +build !appengine
+
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func init() {
+	lockFn = lockFcntl
+}
+
+func lockFcntl(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+	}
+
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, err
+	}
+
+	// This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h.
+	// TODO: move this into the standard syscall package.
+	k := struct {
+		Type   uint16
+		Whence uint16
+		Start  uint32
+		Len    uint32
+		Pid    uint32
+	}{
+		Type:   syscall.F_WRLCK,
+		Whence: uint16(os.SEEK_SET),
+		Start:  0,
+		Len:    0, // 0 means to lock the entire file.
+		Pid:    uint32(os.Getpid()),
+	}
+
+	const F_SETLK = 6 // actual value. syscall package is wrong: golang.org/issue/7059
+	_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(F_SETLK), uintptr(unsafe.Pointer(&k)))
+	if errno != 0 {
+		f.Close()
+		return nil, errno
+	}
+	return &unlocker{f: f, abs: name}, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_plan9.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_plan9.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_plan9.go
new file mode 100644
index 0000000..d841c27
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_plan9.go
@@ -0,0 +1,41 @@
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import (
+	"fmt"
+	"io"
+	"os"
+)
+
+func init() {
+	lockFn = lockPlan9
+}
+
+func lockPlan9(name string) (io.Closer, error) {
+	fi, err := os.Stat(name)
+	if err == nil && fi.Size() > 0 {
+		return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+	}
+
+	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
+	if err != nil {
+		return nil, fmt.Errorf("Lock Create of %s failed: %v", name, err)
+	}
+
+	return &unlocker{f: f, abs: name}, nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/go4/lock/lock_sigzero.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/go4/lock/lock_sigzero.go b/traffic_stats/vendor/github.com/juju/go4/lock/lock_sigzero.go
new file mode 100644
index 0000000..fd3ba2d
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/go4/lock/lock_sigzero.go
@@ -0,0 +1,26 @@
+// +build !appengine
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+/*
+Copyright 2013 The Go Authors
+
+Licensed 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.
+*/
+
+package lock
+
+import "syscall"
+
+func init() {
+	signalZero = syscall.Signal(0)
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/README.md
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/README.md b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/README.md
new file mode 100644
index 0000000..f0c8c56
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/README.md
@@ -0,0 +1,120 @@
+# cookiejar
+--
+    import "github.com/juju/persistent-cookiejar"
+
+Package cookiejar implements an in-memory RFC 6265-compliant http.CookieJar.
+
+This implementation is a fork of net/http/cookiejar which also implements
+methods for dumping the cookies to persistent storage and retrieving them.
+
+## Usage
+
+#### func  DefaultCookieFile
+
+```go
+func DefaultCookieFile() string
+```
+DefaultCookieFile returns the default cookie file to use for persisting cookie
+data. The following names will be used in decending order of preference:
+
+    - the value of the $GOCOOKIES environment variable.
+    - $HOME/.go-cookies
+
+#### type Jar
+
+```go
+type Jar struct {
+}
+```
+
+Jar implements the http.CookieJar interface from the net/http package.
+
+#### func  New
+
+```go
+func New(o *Options) (*Jar, error)
+```
+New returns a new cookie jar. A nil *Options is equivalent to a zero Options.
+
+New will return an error if the cookies could not be loaded from the file for
+any reason than if the file does not exist.
+
+#### func (*Jar) Cookies
+
+```go
+func (j *Jar) Cookies(u *url.URL) (cookies []*http.Cookie)
+```
+Cookies implements the Cookies method of the http.CookieJar interface.
+
+It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
+
+#### func (*Jar) Save
+
+```go
+func (j *Jar) Save() error
+```
+Save saves the cookies to the persistent cookie file. Before the file is
+written, it reads any cookies that have been stored from it and merges them into
+j.
+
+#### func (*Jar) SetCookies
+
+```go
+func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie)
+```
+SetCookies implements the SetCookies method of the http.CookieJar interface.
+
+It does nothing if the URL's scheme is not HTTP or HTTPS.
+
+#### type Options
+
+```go
+type Options struct {
+	// PublicSuffixList is the public suffix list that determines whether
+	// an HTTP server can set a cookie for a domain.
+	//
+	// If this is nil, the public suffix list implementation in golang.org/x/net/publicsuffix
+	// is used.
+	PublicSuffixList PublicSuffixList
+
+	// Filename holds the file to use for storage of the cookies.
+	// If it is empty, the value of DefaultCookieFile will be used.
+	Filename string
+}
+```
+
+Options are the options for creating a new Jar.
+
+#### type PublicSuffixList
+
+```go
+type PublicSuffixList interface {
+	// PublicSuffix returns the public suffix of domain.
+	//
+	// TODO: specify which of the caller and callee is responsible for IP
+	// addresses, for leading and trailing dots, for case sensitivity, and
+	// for IDN/Punycode.
+	PublicSuffix(domain string) string
+
+	// String returns a description of the source of this public suffix
+	// list. The description will typically contain something like a time
+	// stamp or version number.
+	String() string
+}
+```
+
+PublicSuffixList provides the public suffix of a domain. For example:
+
+    - the public suffix of "example.com" is "com",
+    - the public suffix of "foo1.foo2.foo3.co.uk" is "co.uk", and
+    - the public suffix of "bar.pvt.k12.ma.us" is "pvt.k12.ma.us".
+
+Implementations of PublicSuffixList must be safe for concurrent use by multiple
+goroutines.
+
+An implementation that always returns "" is valid and may be useful for testing
+but it is not secure: it means that the HTTP server for foo.com can set a cookie
+for bar.com.
+
+A public suffix list implementation is in the package
+golang.org/x/net/publicsuffix.

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/dependencies.tsv
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/dependencies.tsv b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/dependencies.tsv
new file mode 100644
index 0000000..2f722be
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/dependencies.tsv
@@ -0,0 +1,4 @@
+github.com/juju/go4	git	40d72ab9641a2a8c36a9c46a51e28367115c8e59	2016-02-22T16:32:58Z
+golang.org/x/net	git	b6d7b1396ec874c3b00f6c84cd4301a17c56c8ed	2016-02-17T01:13:48Z
+gopkg.in/errgo.v1	git	66cb46252b94c1f3d65646f54ee8043ab38d766c	2015-10-07T15:31:57Z
+gopkg.in/retry.v1	git	c09f6b86ba4d5d2cf5bdf0665364aec9fd4815db	2016-10-25T18:14:30Z

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/jar.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/jar.go b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/jar.go
new file mode 100644
index 0000000..0a4df82
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/jar.go
@@ -0,0 +1,680 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cookiejar implements an in-memory RFC 6265-compliant http.CookieJar.
+//
+// This implementation is a fork of net/http/cookiejar which also
+// implements methods for dumping the cookies to persistent
+// storage and retrieving them.
+package cookiejar
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/net/publicsuffix"
+	"gopkg.in/errgo.v1"
+)
+
+// PublicSuffixList provides the public suffix of a domain. For example:
+//      - the public suffix of "example.com" is "com",
+//      - the public suffix of "foo1.foo2.foo3.co.uk" is "co.uk", and
+//      - the public suffix of "bar.pvt.k12.ma.us" is "pvt.k12.ma.us".
+//
+// Implementations of PublicSuffixList must be safe for concurrent use by
+// multiple goroutines.
+//
+// An implementation that always returns "" is valid and may be useful for
+// testing but it is not secure: it means that the HTTP server for foo.com can
+// set a cookie for bar.com.
+//
+// A public suffix list implementation is in the package
+// golang.org/x/net/publicsuffix.
+type PublicSuffixList interface {
+	// PublicSuffix returns the public suffix of domain.
+	//
+	// TODO: specify which of the caller and callee is responsible for IP
+	// addresses, for leading and trailing dots, for case sensitivity, and
+	// for IDN/Punycode.
+	PublicSuffix(domain string) string
+
+	// String returns a description of the source of this public suffix
+	// list. The description will typically contain something like a time
+	// stamp or version number.
+	String() string
+}
+
+// Options are the options for creating a new Jar.
+type Options struct {
+	// PublicSuffixList is the public suffix list that determines whether
+	// an HTTP server can set a cookie for a domain.
+	//
+	// If this is nil, the public suffix list implementation in golang.org/x/net/publicsuffix
+	// is used.
+	PublicSuffixList PublicSuffixList
+
+	// Filename holds the file to use for storage of the cookies.
+	// If it is empty, the value of DefaultCookieFile will be used.
+	Filename string
+}
+
+// Jar implements the http.CookieJar interface from the net/http package.
+type Jar struct {
+	// filename holds the file that the cookies were loaded from.
+	filename string
+
+	psList PublicSuffixList
+
+	// mu locks the remaining fields.
+	mu sync.Mutex
+
+	// entries is a set of entries, keyed by their eTLD+1 and subkeyed by
+	// their name/domain/path.
+	entries map[string]map[string]entry
+}
+
+var noOptions Options
+
+// New returns a new cookie jar. A nil *Options is equivalent to a zero
+// Options.
+//
+// New will return an error if the cookies could not be loaded
+// from the file for any reason than if the file does not exist.
+func New(o *Options) (*Jar, error) {
+	return newAtTime(o, time.Now())
+}
+
+// newAtTime is like New but takes the current time as a parameter.
+func newAtTime(o *Options, now time.Time) (*Jar, error) {
+	jar := &Jar{
+		entries: make(map[string]map[string]entry),
+	}
+	if o == nil {
+		o = &noOptions
+	}
+	if jar.psList = o.PublicSuffixList; jar.psList == nil {
+		jar.psList = publicsuffix.List
+	}
+	if jar.filename = o.Filename; jar.filename == "" {
+		jar.filename = DefaultCookieFile()
+	}
+	if err := jar.load(); err != nil {
+		return nil, errgo.Notef(err, "cannot load cookies")
+	}
+	jar.deleteExpired(now)
+	return jar, nil
+}
+
+// homeDir returns the OS-specific home path as specified in the environment.
+func homeDir() string {
+	if runtime.GOOS == "windows" {
+		return filepath.Join(os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"))
+	}
+	return os.Getenv("HOME")
+}
+
+// entry is the internal representation of a cookie.
+//
+// This struct type is not used outside of this package per se, but the exported
+// fields are those of RFC 6265.
+// Note that this structure is marshaled to JSON, so backward-compatibility
+// should be preserved.
+type entry struct {
+	Name       string
+	Value      string
+	Domain     string
+	Path       string
+	Secure     bool
+	HttpOnly   bool
+	Persistent bool
+	HostOnly   bool
+	Expires    time.Time
+	Creation   time.Time
+	LastAccess time.Time
+
+	// Updated records when the cookie was updated.
+	// This is different from creation time because a cookie
+	// can be changed without updating the creation time.
+	Updated time.Time
+
+	// CanonicalHost stores the original canonical host name
+	// that the cookie was associated with. We store this
+	// so that even if the public suffix list changes (for example
+	// when storing/loading cookies) we can still get the correct
+	// jar keys.
+	CanonicalHost string
+}
+
+// id returns the domain;path;name triple of e as an id.
+func (e *entry) id() string {
+	return id(e.Domain, e.Path, e.Name)
+}
+
+// id returns the domain;path;name triple as an id.
+func id(domain, path, name string) string {
+	return fmt.Sprintf("%s;%s;%s", domain, path, name)
+}
+
+// shouldSend determines whether e's cookie qualifies to be included in a
+// request to host/path. It is the caller's responsibility to check if the
+// cookie is expired.
+func (e *entry) shouldSend(https bool, host, path string) bool {
+	return e.domainMatch(host) && e.pathMatch(path) && (https || !e.Secure)
+}
+
+// domainMatch implements "domain-match" of RFC 6265 section 5.1.3.
+func (e *entry) domainMatch(host string) bool {
+	if e.Domain == host {
+		return true
+	}
+	return !e.HostOnly && hasDotSuffix(host, e.Domain)
+}
+
+// pathMatch implements "path-match" according to RFC 6265 section 5.1.4.
+func (e *entry) pathMatch(requestPath string) bool {
+	if requestPath == e.Path {
+		return true
+	}
+	if strings.HasPrefix(requestPath, e.Path) {
+		if e.Path[len(e.Path)-1] == '/' {
+			return true // The "/any/" matches "/any/path" case.
+		} else if requestPath[len(e.Path)] == '/' {
+			return true // The "/any" matches "/any/path" case.
+		}
+	}
+	return false
+}
+
+// hasDotSuffix reports whether s ends in "."+suffix.
+func hasDotSuffix(s, suffix string) bool {
+	return len(s) > len(suffix) && s[len(s)-len(suffix)-1] == '.' && s[len(s)-len(suffix):] == suffix
+}
+
+type byCanonicalHost struct {
+	byPathLength
+}
+
+func (s byCanonicalHost) Less(i, j int) bool {
+	e0, e1 := &s.byPathLength[i], &s.byPathLength[j]
+	if e0.CanonicalHost != e1.CanonicalHost {
+		return e0.CanonicalHost < e1.CanonicalHost
+	}
+	return s.byPathLength.Less(i, j)
+}
+
+// byPathLength is a []entry sort.Interface that sorts according to RFC 6265
+// section 5.4 point 2: by longest path and then by earliest creation time.
+type byPathLength []entry
+
+func (s byPathLength) Len() int { return len(s) }
+
+func (s byPathLength) Less(i, j int) bool {
+	e0, e1 := &s[i], &s[j]
+	if len(e0.Path) != len(e1.Path) {
+		return len(e0.Path) > len(e1.Path)
+	}
+	if !e0.Creation.Equal(e1.Creation) {
+		return e0.Creation.Before(e1.Creation)
+	}
+	// The following are not strictly necessary
+	// but are useful for providing deterministic
+	// behaviour in tests.
+	if e0.Name != e1.Name {
+		return e0.Name < e1.Name
+	}
+	return e0.Value < e1.Value
+}
+
+func (s byPathLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// Cookies implements the Cookies method of the http.CookieJar interface.
+//
+// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
+func (j *Jar) Cookies(u *url.URL) (cookies []*http.Cookie) {
+	return j.cookies(u, time.Now())
+}
+
+// cookies is like Cookies but takes the current time as a parameter.
+func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) {
+	if u.Scheme != "http" && u.Scheme != "https" {
+		return cookies
+	}
+	host, err := canonicalHost(u.Host)
+	if err != nil {
+		return cookies
+	}
+	key := jarKey(host, j.psList)
+
+	j.mu.Lock()
+	defer j.mu.Unlock()
+
+	submap := j.entries[key]
+	if submap == nil {
+		return cookies
+	}
+
+	https := u.Scheme == "https"
+	path := u.Path
+	if path == "" {
+		path = "/"
+	}
+
+	var selected []entry
+	for id, e := range submap {
+		if !e.Expires.After(now) {
+			// Save some space by deleting the value when the cookie
+			// expires. We can't delete the cookie itself because then
+			// we wouldn't know that the cookie had expired when
+			// we merge with another cookie jar.
+			if e.Value != "" {
+				e.Value = ""
+				submap[id] = e
+			}
+			continue
+		}
+		if !e.shouldSend(https, host, path) {
+			continue
+		}
+		e.LastAccess = now
+		submap[id] = e
+		selected = append(selected, e)
+	}
+
+	sort.Sort(byPathLength(selected))
+	for _, e := range selected {
+		cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value})
+	}
+
+	return cookies
+}
+
+// AllCookies returns all cookies in the jar. The returned cookies will
+// have Domain, Expires, HttpOnly, Name, Secure, Path, and Value filled
+// out. Expired cookies will not be returned. This function does not
+// modify the cookie jar.
+func (j *Jar) AllCookies() (cookies []*http.Cookie) {
+	return j.allCookies(time.Now())
+}
+
+// allCookies is like AllCookies but takes the current time as a parameter.
+func (j *Jar) allCookies(now time.Time) []*http.Cookie {
+	var selected []entry
+	j.mu.Lock()
+	defer j.mu.Unlock()
+	for _, submap := range j.entries {
+		for _, e := range submap {
+			if !e.Expires.After(now) {
+				// Do not return expired cookies.
+				continue
+			}
+			selected = append(selected, e)
+		}
+	}
+
+	sort.Sort(byCanonicalHost{byPathLength(selected)})
+	cookies := make([]*http.Cookie, len(selected))
+	for i, e := range selected {
+		// Note: The returned cookies do not contain sufficient
+		// information to recreate the database.
+		cookies[i] = &http.Cookie{
+			Name:     e.Name,
+			Value:    e.Value,
+			Path:     e.Path,
+			Domain:   e.Domain,
+			Expires:  e.Expires,
+			Secure:   e.Secure,
+			HttpOnly: e.HttpOnly,
+		}
+	}
+
+	return cookies
+}
+
+// RemoveCookie removes the cookie matching the name, domain and path
+// specified by c.
+func (j *Jar) RemoveCookie(c *http.Cookie) {
+	j.mu.Lock()
+	defer j.mu.Unlock()
+	id := id(c.Domain, c.Path, c.Name)
+	key := jarKey(c.Domain, j.psList)
+	if e, ok := j.entries[key][id]; ok {
+		e.Value = ""
+		e.Expires = time.Now().Add(-1 * time.Second)
+		j.entries[key][id] = e
+	}
+}
+
+// merge merges all the given entries into j. More recently changed
+// cookies take precedence over older ones.
+func (j *Jar) merge(entries []entry) {
+	for _, e := range entries {
+		if e.CanonicalHost == "" {
+			continue
+		}
+		key := jarKey(e.CanonicalHost, j.psList)
+		id := e.id()
+		submap := j.entries[key]
+		if submap == nil {
+			j.entries[key] = map[string]entry{
+				id: e,
+			}
+			continue
+		}
+		oldEntry, ok := submap[id]
+		if !ok || e.Updated.After(oldEntry.Updated) {
+			submap[id] = e
+		}
+	}
+}
+
+var expiryRemovalDuration = 24 * time.Hour
+
+// deleteExpired deletes all entries that have expired for long enough
+// that we can actually expect there to be no external copies of it that
+// might resurrect the dead cookie.
+func (j *Jar) deleteExpired(now time.Time) {
+	for tld, submap := range j.entries {
+		for id, e := range submap {
+			if !e.Expires.After(now) && !e.Updated.Add(expiryRemovalDuration).After(now) {
+				delete(submap, id)
+			}
+		}
+		if len(submap) == 0 {
+			delete(j.entries, tld)
+		}
+	}
+}
+
+// RemoveAllHost removes any cookies from the jar that were set for the given host.
+func (j *Jar) RemoveAllHost(host string) {
+	host, err := canonicalHost(host)
+	if err != nil {
+		return
+	}
+	key := jarKey(host, j.psList)
+
+	j.mu.Lock()
+	defer j.mu.Unlock()
+
+	expired := time.Now().Add(-1 * time.Second)
+	submap := j.entries[key]
+	for id, e := range submap {
+		if e.CanonicalHost == host {
+			// Save some space by deleting the value when the cookie
+			// expires. We can't delete the cookie itself because then
+			// we wouldn't know that the cookie had expired when
+			// we merge with another cookie jar.
+			e.Value = ""
+			e.Expires = expired
+			submap[id] = e
+		}
+	}
+}
+
+// SetCookies implements the SetCookies method of the http.CookieJar interface.
+//
+// It does nothing if the URL's scheme is not HTTP or HTTPS.
+func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
+	j.setCookies(u, cookies, time.Now())
+}
+
+// setCookies is like SetCookies but takes the current time as parameter.
+func (j *Jar) setCookies(u *url.URL, cookies []*http.Cookie, now time.Time) {
+	if len(cookies) == 0 {
+		return
+	}
+	if u.Scheme != "http" && u.Scheme != "https" {
+		// TODO is this really correct? It might be nice to send
+		// cookies to websocket connections, for example.
+		return
+	}
+	host, err := canonicalHost(u.Host)
+	if err != nil {
+		return
+	}
+	key := jarKey(host, j.psList)
+	defPath := defaultPath(u.Path)
+
+	j.mu.Lock()
+	defer j.mu.Unlock()
+
+	submap := j.entries[key]
+	for _, cookie := range cookies {
+		e, err := j.newEntry(cookie, now, defPath, host)
+		if err != nil {
+			continue
+		}
+		e.CanonicalHost = host
+		id := e.id()
+		if submap == nil {
+			submap = make(map[string]entry)
+			j.entries[key] = submap
+		}
+		if old, ok := submap[id]; ok {
+			e.Creation = old.Creation
+		} else {
+			e.Creation = now
+		}
+		e.Updated = now
+		e.LastAccess = now
+		submap[id] = e
+	}
+}
+
+// canonicalHost strips port from host if present and returns the canonicalized
+// host name.
+func canonicalHost(host string) (string, error) {
+	var err error
+	host = strings.ToLower(host)
+	if hasPort(host) {
+		host, _, err = net.SplitHostPort(host)
+		if err != nil {
+			return "", err
+		}
+	}
+	if strings.HasSuffix(host, ".") {
+		// Strip trailing dot from fully qualified domain names.
+		host = host[:len(host)-1]
+	}
+	return toASCII(host)
+}
+
+// hasPort reports whether host contains a port number. host may be a host
+// name, an IPv4 or an IPv6 address.
+func hasPort(host string) bool {
+	colons := strings.Count(host, ":")
+	if colons == 0 {
+		return false
+	}
+	if colons == 1 {
+		return true
+	}
+	return host[0] == '[' && strings.Contains(host, "]:")
+}
+
+// jarKey returns the key to use for a jar.
+func jarKey(host string, psl PublicSuffixList) string {
+	if isIP(host) {
+		return host
+	}
+
+	var i int
+	if psl == nil {
+		i = strings.LastIndex(host, ".")
+		if i == -1 {
+			return host
+		}
+	} else {
+		suffix := psl.PublicSuffix(host)
+		if suffix == host {
+			return host
+		}
+		i = len(host) - len(suffix)
+		if i <= 0 || host[i-1] != '.' {
+			// The provided public suffix list psl is broken.
+			// Storing cookies under host is a safe stopgap.
+			return host
+		}
+	}
+	prevDot := strings.LastIndex(host[:i-1], ".")
+	return host[prevDot+1:]
+}
+
+// isIP reports whether host is an IP address.
+func isIP(host string) bool {
+	return net.ParseIP(host) != nil
+}
+
+// defaultPath returns the directory part of an URL's path according to
+// RFC 6265 section 5.1.4.
+func defaultPath(path string) string {
+	if len(path) == 0 || path[0] != '/' {
+		return "/" // Path is empty or malformed.
+	}
+
+	i := strings.LastIndex(path, "/") // Path starts with "/", so i != -1.
+	if i == 0 {
+		return "/" // Path has the form "/abc".
+	}
+	return path[:i] // Path is either of form "/abc/xyz" or "/abc/xyz/".
+}
+
+// newEntry creates an entry from a http.Cookie c. now is the current
+// time and is compared to c.Expires to determine deletion of c. defPath
+// and host are the default-path and the canonical host name of the URL
+// c was received from.
+//
+// The returned entry should be removed if its expiry time is in the
+// past. In this case, e may be incomplete, but it will be valid to call
+// e.id (which depends on e's Name, Domain and Path).
+//
+// A malformed c.Domain will result in an error.
+func (j *Jar) newEntry(c *http.Cookie, now time.Time, defPath, host string) (e entry, err error) {
+	e.Name = c.Name
+	if c.Path == "" || c.Path[0] != '/' {
+		e.Path = defPath
+	} else {
+		e.Path = c.Path
+	}
+
+	e.Domain, e.HostOnly, err = j.domainAndType(host, c.Domain)
+	if err != nil {
+		return e, err
+	}
+	// MaxAge takes precedence over Expires.
+	if c.MaxAge != 0 {
+		e.Persistent = true
+		e.Expires = now.Add(time.Duration(c.MaxAge) * time.Second)
+		if c.MaxAge < 0 {
+			return e, nil
+		}
+	} else if c.Expires.IsZero() {
+		e.Expires = endOfTime
+	} else {
+		e.Persistent = true
+		e.Expires = c.Expires
+		if !c.Expires.After(now) {
+			return e, nil
+		}
+	}
+
+	e.Value = c.Value
+	e.Secure = c.Secure
+	e.HttpOnly = c.HttpOnly
+
+	return e, nil
+}
+
+var (
+	errIllegalDomain   = errors.New("cookiejar: illegal cookie domain attribute")
+	errMalformedDomain = errors.New("cookiejar: malformed cookie domain attribute")
+	errNoHostname      = errors.New("cookiejar: no host name available (IP only)")
+)
+
+// endOfTime is the time when session (non-persistent) cookies expire.
+// This instant is representable in most date/time formats (not just
+// Go's time.Time) and should be far enough in the future.
+var endOfTime = time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC)
+
+// domainAndType determines the cookie's domain and hostOnly attribute.
+func (j *Jar) domainAndType(host, domain string) (string, bool, error) {
+	if domain == "" {
+		// No domain attribute in the SetCookie header indicates a
+		// host cookie.
+		return host, true, nil
+	}
+
+	if isIP(host) {
+		// According to RFC 6265 domain-matching includes not being
+		// an IP address.
+		// TODO: This might be relaxed as in common browsers.
+		return "", false, errNoHostname
+	}
+
+	// From here on: If the cookie is valid, it is a domain cookie (with
+	// the one exception of a public suffix below).
+	// See RFC 6265 section 5.2.3.
+	if domain[0] == '.' {
+		domain = domain[1:]
+	}
+
+	if len(domain) == 0 || domain[0] == '.' {
+		// Received either "Domain=." or "Domain=..some.thing",
+		// both are illegal.
+		return "", false, errMalformedDomain
+	}
+	domain = strings.ToLower(domain)
+
+	if domain[len(domain)-1] == '.' {
+		// We received stuff like "Domain=www.example.com.".
+		// Browsers do handle such stuff (actually differently) but
+		// RFC 6265 seems to be clear here (e.g. section 4.1.2.3) in
+		// requiring a reject.  4.1.2.3 is not normative, but
+		// "Domain Matching" (5.1.3) and "Canonicalized Host Names"
+		// (5.1.2) are.
+		return "", false, errMalformedDomain
+	}
+
+	// See RFC 6265 section 5.3 #5.
+	if j.psList != nil {
+		if ps := j.psList.PublicSuffix(domain); ps != "" && !hasDotSuffix(domain, ps) {
+			if host == domain {
+				// This is the one exception in which a cookie
+				// with a domain attribute is a host cookie.
+				return host, true, nil
+			}
+			return "", false, errIllegalDomain
+		}
+	}
+
+	// The domain must domain-match host: www.mycompany.com cannot
+	// set cookies for .ourcompetitors.com.
+	if host != domain && !hasDotSuffix(host, domain) {
+		return "", false, errIllegalDomain
+	}
+
+	return domain, false, nil
+}
+
+// DefaultCookieFile returns the default cookie file to use
+// for persisting cookie data.
+// The following names will be used in decending order of preference:
+//	- the value of the $GOCOOKIES environment variable.
+//	- $HOME/.go-cookies
+func DefaultCookieFile() string {
+	if f := os.Getenv("GOCOOKIES"); f != "" {
+		return f
+	}
+	return filepath.Join(homeDir(), ".go-cookies")
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/punycode.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/punycode.go b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/punycode.go
new file mode 100644
index 0000000..ea7ceb5
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/punycode.go
@@ -0,0 +1,159 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cookiejar
+
+// This file implements the Punycode algorithm from RFC 3492.
+
+import (
+	"fmt"
+	"strings"
+	"unicode/utf8"
+)
+
+// These parameter values are specified in section 5.
+//
+// All computation is done with int32s, so that overflow behavior is identical
+// regardless of whether int is 32-bit or 64-bit.
+const (
+	base        int32 = 36
+	damp        int32 = 700
+	initialBias int32 = 72
+	initialN    int32 = 128
+	skew        int32 = 38
+	tmax        int32 = 26
+	tmin        int32 = 1
+)
+
+// encode encodes a string as specified in section 6.3 and prepends prefix to
+// the result.
+//
+// The "while h < length(input)" line in the specification becomes "for
+// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
+func encode(prefix, s string) (string, error) {
+	output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
+	copy(output, prefix)
+	delta, n, bias := int32(0), initialN, initialBias
+	b, remaining := int32(0), int32(0)
+	for _, r := range s {
+		if r < 0x80 {
+			b++
+			output = append(output, byte(r))
+		} else {
+			remaining++
+		}
+	}
+	h := b
+	if b > 0 {
+		output = append(output, '-')
+	}
+	for remaining != 0 {
+		m := int32(0x7fffffff)
+		for _, r := range s {
+			if m > r && r >= n {
+				m = r
+			}
+		}
+		delta += (m - n) * (h + 1)
+		if delta < 0 {
+			return "", fmt.Errorf("cookiejar: invalid label %q", s)
+		}
+		n = m
+		for _, r := range s {
+			if r < n {
+				delta++
+				if delta < 0 {
+					return "", fmt.Errorf("cookiejar: invalid label %q", s)
+				}
+				continue
+			}
+			if r > n {
+				continue
+			}
+			q := delta
+			for k := base; ; k += base {
+				t := k - bias
+				if t < tmin {
+					t = tmin
+				} else if t > tmax {
+					t = tmax
+				}
+				if q < t {
+					break
+				}
+				output = append(output, encodeDigit(t+(q-t)%(base-t)))
+				q = (q - t) / (base - t)
+			}
+			output = append(output, encodeDigit(q))
+			bias = adapt(delta, h+1, h == b)
+			delta = 0
+			h++
+			remaining--
+		}
+		delta++
+		n++
+	}
+	return string(output), nil
+}
+
+func encodeDigit(digit int32) byte {
+	switch {
+	case 0 <= digit && digit < 26:
+		return byte(digit + 'a')
+	case 26 <= digit && digit < 36:
+		return byte(digit + ('0' - 26))
+	}
+	panic("cookiejar: internal error in punycode encoding")
+}
+
+// adapt is the bias adaptation function specified in section 6.1.
+func adapt(delta, numPoints int32, firstTime bool) int32 {
+	if firstTime {
+		delta /= damp
+	} else {
+		delta /= 2
+	}
+	delta += delta / numPoints
+	k := int32(0)
+	for delta > ((base-tmin)*tmax)/2 {
+		delta /= base - tmin
+		k += base
+	}
+	return k + (base-tmin+1)*delta/(delta+skew)
+}
+
+// Strictly speaking, the remaining code below deals with IDNA (RFC 5890 and
+// friends) and not Punycode (RFC 3492) per se.
+
+// acePrefix is the ASCII Compatible Encoding prefix.
+const acePrefix = "xn--"
+
+// toASCII converts a domain or domain label to its ASCII form. For example,
+// toASCII("b�cher.example.com") is "xn--bcher-kva.example.com", and
+// toASCII("golang") is "golang".
+func toASCII(s string) (string, error) {
+	if ascii(s) {
+		return s, nil
+	}
+	labels := strings.Split(s, ".")
+	for i, label := range labels {
+		if !ascii(label) {
+			a, err := encode(acePrefix, label)
+			if err != nil {
+				return "", err
+			}
+			labels[i] = a
+		}
+	}
+	return strings.Join(labels, "."), nil
+}
+
+func ascii(s string) bool {
+	for i := 0; i < len(s); i++ {
+		if s[i] >= utf8.RuneSelf {
+			return false
+		}
+	}
+	return true
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/serialize.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/juju/persistent-cookiejar/serialize.go b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/serialize.go
new file mode 100644
index 0000000..534f73e
--- /dev/null
+++ b/traffic_stats/vendor/github.com/juju/persistent-cookiejar/serialize.go
@@ -0,0 +1,152 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cookiejar
+
+import (
+	"encoding/json"
+	"io"
+	"log"
+	"os"
+	"sort"
+	"time"
+
+	"gopkg.in/retry.v1"
+
+	filelock "github.com/juju/go4/lock"
+	"gopkg.in/errgo.v1"
+)
+
+// Save saves the cookies to the persistent cookie file.
+// Before the file is written, it reads any cookies that
+// have been stored from it and merges them into j.
+func (j *Jar) Save() error {
+	return j.save(time.Now())
+}
+
+// save is like Save but takes the current time as a parameter.
+func (j *Jar) save(now time.Time) error {
+	locked, err := lockFile(lockFileName(j.filename))
+	if err != nil {
+		return errgo.Mask(err)
+	}
+	defer locked.Close()
+	f, err := os.OpenFile(j.filename, os.O_RDWR|os.O_CREATE, 0600)
+	if err != nil {
+		return errgo.Mask(err)
+	}
+	defer f.Close()
+	// TODO optimization: if the file hasn't changed since we
+	// loaded it, don't bother with the merge step.
+
+	j.mu.Lock()
+	defer j.mu.Unlock()
+	if err := j.mergeFrom(f); err != nil {
+		// The cookie file is probably corrupt.
+		log.Printf("cannot read cookie file to merge it; ignoring it: %v", err)
+	}
+	j.deleteExpired(now)
+	if err := f.Truncate(0); err != nil {
+		return errgo.Notef(err, "cannot truncate file")
+	}
+	if _, err := f.Seek(0, 0); err != nil {
+		return errgo.Mask(err)
+	}
+	return j.writeTo(f)
+}
+
+// load loads the cookies from j.filename. If the file does not exist,
+// no error will be returned and no cookies will be loaded.
+func (j *Jar) load() error {
+	locked, err := lockFile(lockFileName(j.filename))
+	if err != nil {
+		return errgo.Mask(err)
+	}
+	defer locked.Close()
+	f, err := os.Open(j.filename)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	defer f.Close()
+	if err := j.mergeFrom(f); err != nil {
+		return errgo.Mask(err)
+	}
+	return nil
+}
+
+// mergeFrom reads all the cookies from r and stores them in the Jar.
+func (j *Jar) mergeFrom(r io.Reader) error {
+	decoder := json.NewDecoder(r)
+	// Cope with old cookiejar format by just discarding
+	// cookies, but still return an error if it's invalid JSON.
+	var data json.RawMessage
+	if err := decoder.Decode(&data); err != nil {
+		if err == io.EOF {
+			// Empty file.
+			return nil
+		}
+		return err
+	}
+	var entries []entry
+	if err := json.Unmarshal(data, &entries); err != nil {
+		log.Printf("warning: discarding cookies in invalid format (error: %v)", err)
+		return nil
+	}
+	j.merge(entries)
+	return nil
+}
+
+// writeTo writes all the cookies in the jar to w
+// as a JSON array.
+func (j *Jar) writeTo(w io.Writer) error {
+	encoder := json.NewEncoder(w)
+	entries := j.allPersistentEntries()
+	if err := encoder.Encode(entries); err != nil {
+		return err
+	}
+	return nil
+}
+
+// allPersistentEntries returns all the entries in the jar, sorted by primarly by canonical host
+// name and secondarily by path length.
+func (j *Jar) allPersistentEntries() []entry {
+	var entries []entry
+	for _, submap := range j.entries {
+		for _, e := range submap {
+			if e.Persistent {
+				entries = append(entries, e)
+			}
+		}
+	}
+	sort.Sort(byCanonicalHost{entries})
+	return entries
+}
+
+// lockFileName returns the name of the lock file associated with
+// the given path.
+func lockFileName(path string) string {
+	return path + ".lock"
+}
+
+var attempt = retry.LimitTime(3*time.Second, retry.Exponential{
+	Initial:  100 * time.Microsecond,
+	Factor:   1.5,
+	MaxDelay: 100 * time.Millisecond,
+})
+
+func lockFile(path string) (io.Closer, error) {
+	for a := retry.Start(attempt, nil); a.Next(); {
+		locker, err := filelock.Lock(path)
+		if err == nil {
+			return locker, nil
+		}
+		if !a.More() {
+			return nil, errgo.Notef(err, "file locked for too long; giving up")
+		}
+	}
+	panic("unreachable")
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/pkg/errors/.gitignore
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/pkg/errors/.gitignore b/traffic_stats/vendor/github.com/pkg/errors/.gitignore
new file mode 100644
index 0000000..daf913b
--- /dev/null
+++ b/traffic_stats/vendor/github.com/pkg/errors/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/pkg/errors/.travis.yml
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/pkg/errors/.travis.yml b/traffic_stats/vendor/github.com/pkg/errors/.travis.yml
new file mode 100644
index 0000000..567ccdb
--- /dev/null
+++ b/traffic_stats/vendor/github.com/pkg/errors/.travis.yml
@@ -0,0 +1,11 @@
+language: go
+go_import_path: github.com/pkg/errors
+go:
+  - 1.4.3
+  - 1.5.4
+  - 1.6.3
+  - 1.7.3
+  - tip
+
+script:
+  - go test -v ./...

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

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/pkg/errors/README.md
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/pkg/errors/README.md b/traffic_stats/vendor/github.com/pkg/errors/README.md
new file mode 100644
index 0000000..273db3c
--- /dev/null
+++ b/traffic_stats/vendor/github.com/pkg/errors/README.md
@@ -0,0 +1,52 @@
+# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
+
+Package errors provides simple error handling primitives.
+
+`go get github.com/pkg/errors`
+
+The traditional error handling idiom in Go is roughly akin to
+```go
+if err != nil {
+        return err
+}
+```
+which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
+
+## Adding context to an error
+
+The errors.Wrap function returns a new error that adds context to the original error. For example
+```go
+_, err := ioutil.ReadAll(r)
+if err != nil {
+        return errors.Wrap(err, "read failed")
+}
+```
+## Retrieving the cause of an error
+
+Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
+```go
+type causer interface {
+        Cause() error
+}
+```
+`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
+```go
+switch err := errors.Cause(err).(type) {
+case *MyError:
+        // handle specifically
+default:
+        // unknown error
+}
+```
+
+[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
+
+## Contributing
+
+We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
+
+Before proposing a change, please discuss your change by raising an issue.
+
+## Licence
+
+BSD-2-Clause

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/pkg/errors/appveyor.yml
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/pkg/errors/appveyor.yml b/traffic_stats/vendor/github.com/pkg/errors/appveyor.yml
new file mode 100644
index 0000000..a932ead
--- /dev/null
+++ b/traffic_stats/vendor/github.com/pkg/errors/appveyor.yml
@@ -0,0 +1,32 @@
+version: build-{build}.{branch}
+
+clone_folder: C:\gopath\src\github.com\pkg\errors
+shallow_clone: true # for startup speed
+
+environment:
+  GOPATH: C:\gopath
+
+platform:
+  - x64
+
+# http://www.appveyor.com/docs/installed-software
+install:
+  # some helpful output for debugging builds
+  - go version
+  - go env
+  # pre-installed MinGW at C:\MinGW is 32bit only
+  # but MSYS2 at C:\msys64 has mingw64
+  - set PATH=C:\msys64\mingw64\bin;%PATH%
+  - gcc --version
+  - g++ --version
+
+build_script:
+  - go install -v ./...
+
+test_script:
+  - set PATH=C:\gopath\bin;%PATH%
+  - go test -v ./...
+
+#artifacts:
+#  - path: '%GOPATH%\bin\*.exe'
+deploy: off

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4df63f3a/traffic_stats/vendor/github.com/pkg/errors/errors.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/pkg/errors/errors.go b/traffic_stats/vendor/github.com/pkg/errors/errors.go
new file mode 100644
index 0000000..842ee80
--- /dev/null
+++ b/traffic_stats/vendor/github.com/pkg/errors/errors.go
@@ -0,0 +1,269 @@
+// Package errors provides simple error handling primitives.
+//
+// The traditional error handling idiom in Go is roughly akin to
+//
+//     if err != nil {
+//             return err
+//     }
+//
+// which applied recursively up the call stack results in error reports
+// without context or debugging information. The errors package allows
+// programmers to add context to the failure path in their code in a way
+// that does not destroy the original value of the error.
+//
+// Adding context to an error
+//
+// The errors.Wrap function returns a new error that adds context to the
+// original error by recording a stack trace at the point Wrap is called,
+// and the supplied message. For example
+//
+//     _, err := ioutil.ReadAll(r)
+//     if err != nil {
+//             return errors.Wrap(err, "read failed")
+//     }
+//
+// If additional control is required the errors.WithStack and errors.WithMessage
+// functions destructure errors.Wrap into its component operations of annotating
+// an error with a stack trace and an a message, respectively.
+//
+// Retrieving the cause of an error
+//
+// Using errors.Wrap constructs a stack of errors, adding context to the
+// preceding error. Depending on the nature of the error it may be necessary
+// to reverse the operation of errors.Wrap to retrieve the original error
+// for inspection. Any error value which implements this interface
+//
+//     type causer interface {
+//             Cause() error
+//     }
+//
+// can be inspected by errors.Cause. errors.Cause will recursively retrieve
+// the topmost error which does not implement causer, which is assumed to be
+// the original cause. For example:
+//
+//     switch err := errors.Cause(err).(type) {
+//     case *MyError:
+//             // handle specifically
+//     default:
+//             // unknown error
+//     }
+//
+// causer interface is not exported by this package, but is considered a part
+// of stable public API.
+//
+// Formatted printing of errors
+//
+// All error values returned from this package implement fmt.Formatter and can
+// be formatted by the fmt package. The following verbs are supported
+//
+//     %s    print the error. If the error has a Cause it will be
+//           printed recursively
+//     %v    see %s
+//     %+v   extended format. Each Frame of the error's StackTrace will
+//           be printed in detail.
+//
+// Retrieving the stack trace of an error or wrapper
+//
+// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
+// invoked. This information can be retrieved with the following interface.
+//
+//     type stackTracer interface {
+//             StackTrace() errors.StackTrace
+//     }
+//
+// Where errors.StackTrace is defined as
+//
+//     type StackTrace []Frame
+//
+// The Frame type represents a call site in the stack trace. Frame supports
+// the fmt.Formatter interface that can be used for printing information about
+// the stack trace of this error. For example:
+//
+//     if err, ok := err.(stackTracer); ok {
+//             for _, f := range err.StackTrace() {
+//                     fmt.Printf("%+s:%d", f)
+//             }
+//     }
+//
+// stackTracer interface is not exported by this package, but is considered a part
+// of stable public API.
+//
+// See the documentation for Frame.Format for more details.
+package errors
+
+import (
+	"fmt"
+	"io"
+)
+
+// New returns an error with the supplied message.
+// New also records the stack trace at the point it was called.
+func New(message string) error {
+	return &fundamental{
+		msg:   message,
+		stack: callers(),
+	}
+}
+
+// Errorf formats according to a format specifier and returns the string
+// as a value that satisfies error.
+// Errorf also records the stack trace at the point it was called.
+func Errorf(format string, args ...interface{}) error {
+	return &fundamental{
+		msg:   fmt.Sprintf(format, args...),
+		stack: callers(),
+	}
+}
+
+// fundamental is an error that has a message and a stack, but no caller.
+type fundamental struct {
+	msg string
+	*stack
+}
+
+func (f *fundamental) Error() string { return f.msg }
+
+func (f *fundamental) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			io.WriteString(s, f.msg)
+			f.stack.Format(s, verb)
+			return
+		}
+		fallthrough
+	case 's':
+		io.WriteString(s, f.msg)
+	case 'q':
+		fmt.Fprintf(s, "%q", f.msg)
+	}
+}
+
+// WithStack annotates err with a stack trace at the point WithStack was called.
+// If err is nil, WithStack returns nil.
+func WithStack(err error) error {
+	if err == nil {
+		return nil
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+type withStack struct {
+	error
+	*stack
+}
+
+func (w *withStack) Cause() error { return w.error }
+
+func (w *withStack) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			fmt.Fprintf(s, "%+v", w.Cause())
+			w.stack.Format(s, verb)
+			return
+		}
+		fallthrough
+	case 's':
+		io.WriteString(s, w.Error())
+	case 'q':
+		fmt.Fprintf(s, "%q", w.Error())
+	}
+}
+
+// Wrap returns an error annotating err with a stack trace
+// at the point Wrap is called, and the supplied message.
+// If err is nil, Wrap returns nil.
+func Wrap(err error, message string) error {
+	if err == nil {
+		return nil
+	}
+	err = &withMessage{
+		cause: err,
+		msg:   message,
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+// Wrapf returns an error annotating err with a stack trace
+// at the point Wrapf is call, and the format specifier.
+// If err is nil, Wrapf returns nil.
+func Wrapf(err error, format string, args ...interface{}) error {
+	if err == nil {
+		return nil
+	}
+	err = &withMessage{
+		cause: err,
+		msg:   fmt.Sprintf(format, args...),
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+// WithMessage annotates err with a new message.
+// If err is nil, WithMessage returns nil.
+func WithMessage(err error, message string) error {
+	if err == nil {
+		return nil
+	}
+	return &withMessage{
+		cause: err,
+		msg:   message,
+	}
+}
+
+type withMessage struct {
+	cause error
+	msg   string
+}
+
+func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
+func (w *withMessage) Cause() error  { return w.cause }
+
+func (w *withMessage) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			fmt.Fprintf(s, "%+v\n", w.Cause())
+			io.WriteString(s, w.msg)
+			return
+		}
+		fallthrough
+	case 's', 'q':
+		io.WriteString(s, w.Error())
+	}
+}
+
+// Cause returns the underlying cause of the error, if possible.
+// An error value has a cause if it implements the following
+// interface:
+//
+//     type causer interface {
+//            Cause() error
+//     }
+//
+// If the error does not implement Cause, the original error will
+// be returned. If the error is nil, nil will be returned without further
+// investigation.
+func Cause(err error) error {
+	type causer interface {
+		Cause() error
+	}
+
+	for err != nil {
+		cause, ok := err.(causer)
+		if !ok {
+			break
+		}
+		err = cause.Cause()
+	}
+	return err
+}