VOL-381 add unum container to support ONOS cluster formation under swarm

Change-Id: Ic260edda19bb199ed040f05164ab605f28c919d0
diff --git a/unum/vendor/golang.org/x/text/transform/examples_test.go b/unum/vendor/golang.org/x/text/transform/examples_test.go
new file mode 100644
index 0000000..f2e284d
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/transform/examples_test.go
@@ -0,0 +1,37 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package transform_test
+
+import (
+	"fmt"
+	"unicode"
+
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/norm"
+)
+
+func ExampleRemoveFunc() {
+	input := []byte(`tschüß; до свидания`)
+
+	b := make([]byte, len(input))
+
+	t := transform.RemoveFunc(unicode.IsSpace)
+	n, _, _ := t.Transform(b, input, true)
+	fmt.Println(string(b[:n]))
+
+	t = transform.RemoveFunc(func(r rune) bool {
+		return !unicode.Is(unicode.Latin, r)
+	})
+	n, _, _ = t.Transform(b, input, true)
+	fmt.Println(string(b[:n]))
+
+	n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true)
+	fmt.Println(string(b[:n]))
+
+	// Output:
+	// tschüß;досвидания
+	// tschüß
+	// tschuß
+}
diff --git a/unum/vendor/golang.org/x/text/transform/transform.go b/unum/vendor/golang.org/x/text/transform/transform.go
new file mode 100644
index 0000000..fe47b9b
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/transform/transform.go
@@ -0,0 +1,705 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package transform provides reader and writer wrappers that transform the
+// bytes passing through as well as various transformations. Example
+// transformations provided by other packages include normalization and
+// conversion between character sets.
+package transform // import "golang.org/x/text/transform"
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"unicode/utf8"
+)
+
+var (
+	// ErrShortDst means that the destination buffer was too short to
+	// receive all of the transformed bytes.
+	ErrShortDst = errors.New("transform: short destination buffer")
+
+	// ErrShortSrc means that the source buffer has insufficient data to
+	// complete the transformation.
+	ErrShortSrc = errors.New("transform: short source buffer")
+
+	// ErrEndOfSpan means that the input and output (the transformed input)
+	// are not identical.
+	ErrEndOfSpan = errors.New("transform: input and output are not identical")
+
+	// errInconsistentByteCount means that Transform returned success (nil
+	// error) but also returned nSrc inconsistent with the src argument.
+	errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
+
+	// errShortInternal means that an internal buffer is not large enough
+	// to make progress and the Transform operation must be aborted.
+	errShortInternal = errors.New("transform: short internal buffer")
+)
+
+// Transformer transforms bytes.
+type Transformer interface {
+	// Transform writes to dst the transformed bytes read from src, and
+	// returns the number of dst bytes written and src bytes read. The
+	// atEOF argument tells whether src represents the last bytes of the
+	// input.
+	//
+	// Callers should always process the nDst bytes produced and account
+	// for the nSrc bytes consumed before considering the error err.
+	//
+	// A nil error means that all of the transformed bytes (whether freshly
+	// transformed from src or left over from previous Transform calls)
+	// were written to dst. A nil error can be returned regardless of
+	// whether atEOF is true. If err is nil then nSrc must equal len(src);
+	// the converse is not necessarily true.
+	//
+	// ErrShortDst means that dst was too short to receive all of the
+	// transformed bytes. ErrShortSrc means that src had insufficient data
+	// to complete the transformation. If both conditions apply, then
+	// either error may be returned. Other than the error conditions listed
+	// here, implementations are free to report other errors that arise.
+	Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
+
+	// Reset resets the state and allows a Transformer to be reused.
+	Reset()
+}
+
+// SpanningTransformer extends the Transformer interface with a Span method
+// that determines how much of the input already conforms to the Transformer.
+type SpanningTransformer interface {
+	Transformer
+
+	// Span returns a position in src such that transforming src[:n] results in
+	// identical output src[:n] for these bytes. It does not necessarily return
+	// the largest such n. The atEOF argument tells whether src represents the
+	// last bytes of the input.
+	//
+	// Callers should always account for the n bytes consumed before
+	// considering the error err.
+	//
+	// A nil error means that all input bytes are known to be identical to the
+	// output produced by the Transformer. A nil error can be be returned
+	// regardless of whether atEOF is true. If err is nil, then then n must
+	// equal len(src); the converse is not necessarily true.
+	//
+	// ErrEndOfSpan means that the Transformer output may differ from the
+	// input after n bytes. Note that n may be len(src), meaning that the output
+	// would contain additional bytes after otherwise identical output.
+	// ErrShortSrc means that src had insufficient data to determine whether the
+	// remaining bytes would change. Other than the error conditions listed
+	// here, implementations are free to report other errors that arise.
+	//
+	// Calling Span can modify the Transformer state as a side effect. In
+	// effect, it does the transformation just as calling Transform would, only
+	// without copying to a destination buffer and only up to a point it can
+	// determine the input and output bytes are the same. This is obviously more
+	// limited than calling Transform, but can be more efficient in terms of
+	// copying and allocating buffers. Calls to Span and Transform may be
+	// interleaved.
+	Span(src []byte, atEOF bool) (n int, err error)
+}
+
+// NopResetter can be embedded by implementations of Transformer to add a nop
+// Reset method.
+type NopResetter struct{}
+
+// Reset implements the Reset method of the Transformer interface.
+func (NopResetter) Reset() {}
+
+// Reader wraps another io.Reader by transforming the bytes read.
+type Reader struct {
+	r   io.Reader
+	t   Transformer
+	err error
+
+	// dst[dst0:dst1] contains bytes that have been transformed by t but
+	// not yet copied out via Read.
+	dst        []byte
+	dst0, dst1 int
+
+	// src[src0:src1] contains bytes that have been read from r but not
+	// yet transformed through t.
+	src        []byte
+	src0, src1 int
+
+	// transformComplete is whether the transformation is complete,
+	// regardless of whether or not it was successful.
+	transformComplete bool
+}
+
+const defaultBufSize = 4096
+
+// NewReader returns a new Reader that wraps r by transforming the bytes read
+// via t. It calls Reset on t.
+func NewReader(r io.Reader, t Transformer) *Reader {
+	t.Reset()
+	return &Reader{
+		r:   r,
+		t:   t,
+		dst: make([]byte, defaultBufSize),
+		src: make([]byte, defaultBufSize),
+	}
+}
+
+// Read implements the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+	n, err := 0, error(nil)
+	for {
+		// Copy out any transformed bytes and return the final error if we are done.
+		if r.dst0 != r.dst1 {
+			n = copy(p, r.dst[r.dst0:r.dst1])
+			r.dst0 += n
+			if r.dst0 == r.dst1 && r.transformComplete {
+				return n, r.err
+			}
+			return n, nil
+		} else if r.transformComplete {
+			return 0, r.err
+		}
+
+		// Try to transform some source bytes, or to flush the transformer if we
+		// are out of source bytes. We do this even if r.r.Read returned an error.
+		// As the io.Reader documentation says, "process the n > 0 bytes returned
+		// before considering the error".
+		if r.src0 != r.src1 || r.err != nil {
+			r.dst0 = 0
+			r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
+			r.src0 += n
+
+			switch {
+			case err == nil:
+				if r.src0 != r.src1 {
+					r.err = errInconsistentByteCount
+				}
+				// The Transform call was successful; we are complete if we
+				// cannot read more bytes into src.
+				r.transformComplete = r.err != nil
+				continue
+			case err == ErrShortDst && (r.dst1 != 0 || n != 0):
+				// Make room in dst by copying out, and try again.
+				continue
+			case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
+				// Read more bytes into src via the code below, and try again.
+			default:
+				r.transformComplete = true
+				// The reader error (r.err) takes precedence over the
+				// transformer error (err) unless r.err is nil or io.EOF.
+				if r.err == nil || r.err == io.EOF {
+					r.err = err
+				}
+				continue
+			}
+		}
+
+		// Move any untransformed source bytes to the start of the buffer
+		// and read more bytes.
+		if r.src0 != 0 {
+			r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
+		}
+		n, r.err = r.r.Read(r.src[r.src1:])
+		r.src1 += n
+	}
+}
+
+// TODO: implement ReadByte (and ReadRune??).
+
+// Writer wraps another io.Writer by transforming the bytes read.
+// The user needs to call Close to flush unwritten bytes that may
+// be buffered.
+type Writer struct {
+	w   io.Writer
+	t   Transformer
+	dst []byte
+
+	// src[:n] contains bytes that have not yet passed through t.
+	src []byte
+	n   int
+}
+
+// NewWriter returns a new Writer that wraps w by transforming the bytes written
+// via t. It calls Reset on t.
+func NewWriter(w io.Writer, t Transformer) *Writer {
+	t.Reset()
+	return &Writer{
+		w:   w,
+		t:   t,
+		dst: make([]byte, defaultBufSize),
+		src: make([]byte, defaultBufSize),
+	}
+}
+
+// Write implements the io.Writer interface. If there are not enough
+// bytes available to complete a Transform, the bytes will be buffered
+// for the next write. Call Close to convert the remaining bytes.
+func (w *Writer) Write(data []byte) (n int, err error) {
+	src := data
+	if w.n > 0 {
+		// Append bytes from data to the last remainder.
+		// TODO: limit the amount copied on first try.
+		n = copy(w.src[w.n:], data)
+		w.n += n
+		src = w.src[:w.n]
+	}
+	for {
+		nDst, nSrc, err := w.t.Transform(w.dst, src, false)
+		if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+			return n, werr
+		}
+		src = src[nSrc:]
+		if w.n == 0 {
+			n += nSrc
+		} else if len(src) <= n {
+			// Enough bytes from w.src have been consumed. We make src point
+			// to data instead to reduce the copying.
+			w.n = 0
+			n -= len(src)
+			src = data[n:]
+			if n < len(data) && (err == nil || err == ErrShortSrc) {
+				continue
+			}
+		}
+		switch err {
+		case ErrShortDst:
+			// This error is okay as long as we are making progress.
+			if nDst > 0 || nSrc > 0 {
+				continue
+			}
+		case ErrShortSrc:
+			if len(src) < len(w.src) {
+				m := copy(w.src, src)
+				// If w.n > 0, bytes from data were already copied to w.src and n
+				// was already set to the number of bytes consumed.
+				if w.n == 0 {
+					n += m
+				}
+				w.n = m
+				err = nil
+			} else if nDst > 0 || nSrc > 0 {
+				// Not enough buffer to store the remainder. Keep processing as
+				// long as there is progress. Without this case, transforms that
+				// require a lookahead larger than the buffer may result in an
+				// error. This is not something one may expect to be common in
+				// practice, but it may occur when buffers are set to small
+				// sizes during testing.
+				continue
+			}
+		case nil:
+			if w.n > 0 {
+				err = errInconsistentByteCount
+			}
+		}
+		return n, err
+	}
+}
+
+// Close implements the io.Closer interface.
+func (w *Writer) Close() error {
+	src := w.src[:w.n]
+	for {
+		nDst, nSrc, err := w.t.Transform(w.dst, src, true)
+		if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+			return werr
+		}
+		if err != ErrShortDst {
+			return err
+		}
+		src = src[nSrc:]
+	}
+}
+
+type nop struct{ NopResetter }
+
+func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := copy(dst, src)
+	if n < len(src) {
+		err = ErrShortDst
+	}
+	return n, n, err
+}
+
+func (nop) Span(src []byte, atEOF bool) (n int, err error) {
+	return len(src), nil
+}
+
+type discard struct{ NopResetter }
+
+func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	return 0, len(src), nil
+}
+
+var (
+	// Discard is a Transformer for which all Transform calls succeed
+	// by consuming all bytes and writing nothing.
+	Discard Transformer = discard{}
+
+	// Nop is a SpanningTransformer that copies src to dst.
+	Nop SpanningTransformer = nop{}
+)
+
+// chain is a sequence of links. A chain with N Transformers has N+1 links and
+// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
+// buffers given to chain.Transform and the middle N-1 buffers are intermediate
+// buffers owned by the chain. The i'th link transforms bytes from the i'th
+// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
+// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
+type chain struct {
+	link []link
+	err  error
+	// errStart is the index at which the error occurred plus 1. Processing
+	// errStart at this level at the next call to Transform. As long as
+	// errStart > 0, chain will not consume any more source bytes.
+	errStart int
+}
+
+func (c *chain) fatalError(errIndex int, err error) {
+	if i := errIndex + 1; i > c.errStart {
+		c.errStart = i
+		c.err = err
+	}
+}
+
+type link struct {
+	t Transformer
+	// b[p:n] holds the bytes to be transformed by t.
+	b []byte
+	p int
+	n int
+}
+
+func (l *link) src() []byte {
+	return l.b[l.p:l.n]
+}
+
+func (l *link) dst() []byte {
+	return l.b[l.n:]
+}
+
+// Chain returns a Transformer that applies t in sequence.
+func Chain(t ...Transformer) Transformer {
+	if len(t) == 0 {
+		return nop{}
+	}
+	c := &chain{link: make([]link, len(t)+1)}
+	for i, tt := range t {
+		c.link[i].t = tt
+	}
+	// Allocate intermediate buffers.
+	b := make([][defaultBufSize]byte, len(t)-1)
+	for i := range b {
+		c.link[i+1].b = b[i][:]
+	}
+	return c
+}
+
+// Reset resets the state of Chain. It calls Reset on all the Transformers.
+func (c *chain) Reset() {
+	for i, l := range c.link {
+		if l.t != nil {
+			l.t.Reset()
+		}
+		c.link[i].p, c.link[i].n = 0, 0
+	}
+}
+
+// TODO: make chain use Span (is going to be fun to implement!)
+
+// Transform applies the transformers of c in sequence.
+func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	// Set up src and dst in the chain.
+	srcL := &c.link[0]
+	dstL := &c.link[len(c.link)-1]
+	srcL.b, srcL.p, srcL.n = src, 0, len(src)
+	dstL.b, dstL.n = dst, 0
+	var lastFull, needProgress bool // for detecting progress
+
+	// i is the index of the next Transformer to apply, for i in [low, high].
+	// low is the lowest index for which c.link[low] may still produce bytes.
+	// high is the highest index for which c.link[high] has a Transformer.
+	// The error returned by Transform determines whether to increase or
+	// decrease i. We try to completely fill a buffer before converting it.
+	for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
+		in, out := &c.link[i], &c.link[i+1]
+		nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
+		out.n += nDst
+		in.p += nSrc
+		if i > 0 && in.p == in.n {
+			in.p, in.n = 0, 0
+		}
+		needProgress, lastFull = lastFull, false
+		switch err0 {
+		case ErrShortDst:
+			// Process the destination buffer next. Return if we are already
+			// at the high index.
+			if i == high {
+				return dstL.n, srcL.p, ErrShortDst
+			}
+			if out.n != 0 {
+				i++
+				// If the Transformer at the next index is not able to process any
+				// source bytes there is nothing that can be done to make progress
+				// and the bytes will remain unprocessed. lastFull is used to
+				// detect this and break out of the loop with a fatal error.
+				lastFull = true
+				continue
+			}
+			// The destination buffer was too small, but is completely empty.
+			// Return a fatal error as this transformation can never complete.
+			c.fatalError(i, errShortInternal)
+		case ErrShortSrc:
+			if i == 0 {
+				// Save ErrShortSrc in err. All other errors take precedence.
+				err = ErrShortSrc
+				break
+			}
+			// Source bytes were depleted before filling up the destination buffer.
+			// Verify we made some progress, move the remaining bytes to the errStart
+			// and try to get more source bytes.
+			if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
+				// There were not enough source bytes to proceed while the source
+				// buffer cannot hold any more bytes. Return a fatal error as this
+				// transformation can never complete.
+				c.fatalError(i, errShortInternal)
+				break
+			}
+			// in.b is an internal buffer and we can make progress.
+			in.p, in.n = 0, copy(in.b, in.src())
+			fallthrough
+		case nil:
+			// if i == low, we have depleted the bytes at index i or any lower levels.
+			// In that case we increase low and i. In all other cases we decrease i to
+			// fetch more bytes before proceeding to the next index.
+			if i > low {
+				i--
+				continue
+			}
+		default:
+			c.fatalError(i, err0)
+		}
+		// Exhausted level low or fatal error: increase low and continue
+		// to process the bytes accepted so far.
+		i++
+		low = i
+	}
+
+	// If c.errStart > 0, this means we found a fatal error.  We will clear
+	// all upstream buffers. At this point, no more progress can be made
+	// downstream, as Transform would have bailed while handling ErrShortDst.
+	if c.errStart > 0 {
+		for i := 1; i < c.errStart; i++ {
+			c.link[i].p, c.link[i].n = 0, 0
+		}
+		err, c.errStart, c.err = c.err, 0, nil
+	}
+	return dstL.n, srcL.p, err
+}
+
+// Deprecated: use runes.Remove instead.
+func RemoveFunc(f func(r rune) bool) Transformer {
+	return removeF(f)
+}
+
+type removeF func(r rune) bool
+
+func (removeF) Reset() {}
+
+// Transform implements the Transformer interface.
+func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
+
+		if r = rune(src[0]); r < utf8.RuneSelf {
+			sz = 1
+		} else {
+			r, sz = utf8.DecodeRune(src)
+
+			if sz == 1 {
+				// Invalid rune.
+				if !atEOF && !utf8.FullRune(src) {
+					err = ErrShortSrc
+					break
+				}
+				// We replace illegal bytes with RuneError. Not doing so might
+				// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
+				// The resulting byte sequence may subsequently contain runes
+				// for which t(r) is true that were passed unnoticed.
+				if !t(r) {
+					if nDst+3 > len(dst) {
+						err = ErrShortDst
+						break
+					}
+					nDst += copy(dst[nDst:], "\uFFFD")
+				}
+				nSrc++
+				continue
+			}
+		}
+
+		if !t(r) {
+			if nDst+sz > len(dst) {
+				err = ErrShortDst
+				break
+			}
+			nDst += copy(dst[nDst:], src[:sz])
+		}
+		nSrc += sz
+	}
+	return
+}
+
+// grow returns a new []byte that is longer than b, and copies the first n bytes
+// of b to the start of the new slice.
+func grow(b []byte, n int) []byte {
+	m := len(b)
+	if m <= 32 {
+		m = 64
+	} else if m <= 256 {
+		m *= 2
+	} else {
+		m += m >> 1
+	}
+	buf := make([]byte, m)
+	copy(buf, b[:n])
+	return buf
+}
+
+const initialBufSize = 128
+
+// String returns a string with the result of converting s[:n] using t, where
+// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
+func String(t Transformer, s string) (result string, n int, err error) {
+	t.Reset()
+	if s == "" {
+		// Fast path for the common case for empty input. Results in about a
+		// 86% reduction of running time for BenchmarkStringLowerEmpty.
+		if _, _, err := t.Transform(nil, nil, true); err == nil {
+			return "", 0, nil
+		}
+	}
+
+	// Allocate only once. Note that both dst and src escape when passed to
+	// Transform.
+	buf := [2 * initialBufSize]byte{}
+	dst := buf[:initialBufSize:initialBufSize]
+	src := buf[initialBufSize : 2*initialBufSize]
+
+	// The input string s is transformed in multiple chunks (starting with a
+	// chunk size of initialBufSize). nDst and nSrc are per-chunk (or
+	// per-Transform-call) indexes, pDst and pSrc are overall indexes.
+	nDst, nSrc := 0, 0
+	pDst, pSrc := 0, 0
+
+	// pPrefix is the length of a common prefix: the first pPrefix bytes of the
+	// result will equal the first pPrefix bytes of s. It is not guaranteed to
+	// be the largest such value, but if pPrefix, len(result) and len(s) are
+	// all equal after the final transform (i.e. calling Transform with atEOF
+	// being true returned nil error) then we don't need to allocate a new
+	// result string.
+	pPrefix := 0
+	for {
+		// Invariant: pDst == pPrefix && pSrc == pPrefix.
+
+		n := copy(src, s[pSrc:])
+		nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
+		pDst += nDst
+		pSrc += nSrc
+
+		// TODO:  let transformers implement an optional Spanner interface, akin
+		// to norm's QuickSpan. This would even allow us to avoid any allocation.
+		if !bytes.Equal(dst[:nDst], src[:nSrc]) {
+			break
+		}
+		pPrefix = pSrc
+		if err == ErrShortDst {
+			// A buffer can only be short if a transformer modifies its input.
+			break
+		} else if err == ErrShortSrc {
+			if nSrc == 0 {
+				// No progress was made.
+				break
+			}
+			// Equal so far and !atEOF, so continue checking.
+		} else if err != nil || pPrefix == len(s) {
+			return string(s[:pPrefix]), pPrefix, err
+		}
+	}
+	// Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
+
+	// We have transformed the first pSrc bytes of the input s to become pDst
+	// transformed bytes. Those transformed bytes are discontiguous: the first
+	// pPrefix of them equal s[:pPrefix] and the last nDst of them equal
+	// dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
+	// that they become one contiguous slice: dst[:pDst].
+	if pPrefix != 0 {
+		newDst := dst
+		if pDst > len(newDst) {
+			newDst = make([]byte, len(s)+nDst-nSrc)
+		}
+		copy(newDst[pPrefix:pDst], dst[:nDst])
+		copy(newDst[:pPrefix], s[:pPrefix])
+		dst = newDst
+	}
+
+	// Prevent duplicate Transform calls with atEOF being true at the end of
+	// the input. Also return if we have an unrecoverable error.
+	if (err == nil && pSrc == len(s)) ||
+		(err != nil && err != ErrShortDst && err != ErrShortSrc) {
+		return string(dst[:pDst]), pSrc, err
+	}
+
+	// Transform the remaining input, growing dst and src buffers as necessary.
+	for {
+		n := copy(src, s[pSrc:])
+		nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
+		pDst += nDst
+		pSrc += nSrc
+
+		// If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
+		// make progress. This may avoid excessive allocations.
+		if err == ErrShortDst {
+			if nDst == 0 {
+				dst = grow(dst, pDst)
+			}
+		} else if err == ErrShortSrc {
+			if nSrc == 0 {
+				src = grow(src, 0)
+			}
+		} else if err != nil || pSrc == len(s) {
+			return string(dst[:pDst]), pSrc, err
+		}
+	}
+}
+
+// Bytes returns a new byte slice with the result of converting b[:n] using t,
+// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
+func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
+	return doAppend(t, 0, make([]byte, len(b)), b)
+}
+
+// Append appends the result of converting src[:n] using t to dst, where
+// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
+func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
+	if len(dst) == cap(dst) {
+		n := len(src) + len(dst) // It is okay for this to be 0.
+		b := make([]byte, n)
+		dst = b[:copy(b, dst)]
+	}
+	return doAppend(t, len(dst), dst[:cap(dst)], src)
+}
+
+func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
+	t.Reset()
+	pSrc := 0
+	for {
+		nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
+		pDst += nDst
+		pSrc += nSrc
+		if err != ErrShortDst {
+			return dst[:pDst], pSrc, err
+		}
+
+		// Grow the destination buffer, but do not grow as long as we can make
+		// progress. This may avoid excessive allocations.
+		if nDst == 0 {
+			dst = grow(dst, pDst)
+		}
+	}
+}
diff --git a/unum/vendor/golang.org/x/text/transform/transform_test.go b/unum/vendor/golang.org/x/text/transform/transform_test.go
new file mode 100644
index 0000000..771633d
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/transform/transform_test.go
@@ -0,0 +1,1317 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package transform
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+	"unicode/utf8"
+
+	"golang.org/x/text/internal/testtext"
+)
+
+type lowerCaseASCII struct{ NopResetter }
+
+func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := len(src)
+	if n > len(dst) {
+		n, err = len(dst), ErrShortDst
+	}
+	for i, c := range src[:n] {
+		if 'A' <= c && c <= 'Z' {
+			c += 'a' - 'A'
+		}
+		dst[i] = c
+	}
+	return n, n, err
+}
+
+// lowerCaseASCIILookahead lowercases the string and reports ErrShortSrc as long
+// as the input is not atEOF.
+type lowerCaseASCIILookahead struct{ NopResetter }
+
+func (lowerCaseASCIILookahead) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := len(src)
+	if n > len(dst) {
+		n, err = len(dst), ErrShortDst
+	}
+	for i, c := range src[:n] {
+		if 'A' <= c && c <= 'Z' {
+			c += 'a' - 'A'
+		}
+		dst[i] = c
+	}
+	if !atEOF {
+		err = ErrShortSrc
+	}
+	return n, n, err
+}
+
+var errYouMentionedX = errors.New("you mentioned X")
+
+type dontMentionX struct{ NopResetter }
+
+func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := len(src)
+	if n > len(dst) {
+		n, err = len(dst), ErrShortDst
+	}
+	for i, c := range src[:n] {
+		if c == 'X' {
+			return i, i, errYouMentionedX
+		}
+		dst[i] = c
+	}
+	return n, n, err
+}
+
+var errAtEnd = errors.New("error after all text")
+
+type errorAtEnd struct{ NopResetter }
+
+func (errorAtEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := copy(dst, src)
+	if n < len(src) {
+		return n, n, ErrShortDst
+	}
+	if atEOF {
+		return n, n, errAtEnd
+	}
+	return n, n, nil
+}
+
+type replaceWithConstant struct {
+	replacement string
+	written     int
+}
+
+func (t *replaceWithConstant) Reset() {
+	t.written = 0
+}
+
+func (t *replaceWithConstant) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	if atEOF {
+		nDst = copy(dst, t.replacement[t.written:])
+		t.written += nDst
+		if t.written < len(t.replacement) {
+			err = ErrShortDst
+		}
+	}
+	return nDst, len(src), err
+}
+
+type addAnXAtTheEnd struct{ NopResetter }
+
+func (addAnXAtTheEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	n := copy(dst, src)
+	if n < len(src) {
+		return n, n, ErrShortDst
+	}
+	if !atEOF {
+		return n, n, nil
+	}
+	if len(dst) == n {
+		return n, n, ErrShortDst
+	}
+	dst[n] = 'X'
+	return n + 1, n, nil
+}
+
+// doublerAtEOF is a strange Transformer that transforms "this" to "tthhiiss",
+// but only if atEOF is true.
+type doublerAtEOF struct{ NopResetter }
+
+func (doublerAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	if !atEOF {
+		return 0, 0, ErrShortSrc
+	}
+	for i, c := range src {
+		if 2*i+2 >= len(dst) {
+			return 2 * i, i, ErrShortDst
+		}
+		dst[2*i+0] = c
+		dst[2*i+1] = c
+	}
+	return 2 * len(src), len(src), nil
+}
+
+// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb"
+// is encoded as "2a10b". The decoding is assumed to not contain any numbers.
+
+type rleDecode struct{ NopResetter }
+
+func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+loop:
+	for len(src) > 0 {
+		n := 0
+		for i, c := range src {
+			if '0' <= c && c <= '9' {
+				n = 10*n + int(c-'0')
+				continue
+			}
+			if i == 0 {
+				return nDst, nSrc, errors.New("rleDecode: bad input")
+			}
+			if n > len(dst) {
+				return nDst, nSrc, ErrShortDst
+			}
+			for j := 0; j < n; j++ {
+				dst[j] = c
+			}
+			dst, src = dst[n:], src[i+1:]
+			nDst, nSrc = nDst+n, nSrc+i+1
+			continue loop
+		}
+		if atEOF {
+			return nDst, nSrc, errors.New("rleDecode: bad input")
+		}
+		return nDst, nSrc, ErrShortSrc
+	}
+	return nDst, nSrc, nil
+}
+
+type rleEncode struct {
+	NopResetter
+
+	// allowStutter means that "xxxxxxxx" can be encoded as "5x3x"
+	// instead of always as "8x".
+	allowStutter bool
+}
+
+func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for len(src) > 0 {
+		n, c0 := len(src), src[0]
+		for i, c := range src[1:] {
+			if c != c0 {
+				n = i + 1
+				break
+			}
+		}
+		if n == len(src) && !atEOF && !e.allowStutter {
+			return nDst, nSrc, ErrShortSrc
+		}
+		s := strconv.Itoa(n)
+		if len(s) >= len(dst) {
+			return nDst, nSrc, ErrShortDst
+		}
+		copy(dst, s)
+		dst[len(s)] = c0
+		dst, src = dst[len(s)+1:], src[n:]
+		nDst, nSrc = nDst+len(s)+1, nSrc+n
+	}
+	return nDst, nSrc, nil
+}
+
+// trickler consumes all input bytes, but writes a single byte at a time to dst.
+type trickler []byte
+
+func (t *trickler) Reset() {
+	*t = nil
+}
+
+func (t *trickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	*t = append(*t, src...)
+	if len(*t) == 0 {
+		return 0, 0, nil
+	}
+	if len(dst) == 0 {
+		return 0, len(src), ErrShortDst
+	}
+	dst[0] = (*t)[0]
+	*t = (*t)[1:]
+	if len(*t) > 0 {
+		err = ErrShortDst
+	}
+	return 1, len(src), err
+}
+
+// delayedTrickler is like trickler, but delays writing output to dst. This is
+// highly unlikely to be relevant in practice, but it seems like a good idea
+// to have some tolerance as long as progress can be detected.
+type delayedTrickler []byte
+
+func (t *delayedTrickler) Reset() {
+	*t = nil
+}
+
+func (t *delayedTrickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	if len(*t) > 0 && len(dst) > 0 {
+		dst[0] = (*t)[0]
+		*t = (*t)[1:]
+		nDst = 1
+	}
+	*t = append(*t, src...)
+	if len(*t) > 0 {
+		err = ErrShortDst
+	}
+	return nDst, len(src), err
+}
+
+type testCase struct {
+	desc     string
+	t        Transformer
+	src      string
+	dstSize  int
+	srcSize  int
+	ioSize   int
+	wantStr  string
+	wantErr  error
+	wantIter int // number of iterations taken; 0 means we don't care.
+}
+
+func (t testCase) String() string {
+	return tstr(t.t) + "; " + t.desc
+}
+
+func tstr(t Transformer) string {
+	if stringer, ok := t.(fmt.Stringer); ok {
+		return stringer.String()
+	}
+	s := fmt.Sprintf("%T", t)
+	return s[1+strings.Index(s, "."):]
+}
+
+func (c chain) String() string {
+	buf := &bytes.Buffer{}
+	buf.WriteString("Chain(")
+	for i, l := range c.link[:len(c.link)-1] {
+		if i != 0 {
+			fmt.Fprint(buf, ", ")
+		}
+		buf.WriteString(tstr(l.t))
+	}
+	buf.WriteString(")")
+	return buf.String()
+}
+
+var testCases = []testCase{
+	{
+		desc:    "empty",
+		t:       lowerCaseASCII{},
+		src:     "",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "",
+	},
+
+	{
+		desc:    "basic",
+		t:       lowerCaseASCII{},
+		src:     "Hello WORLD.",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small dst",
+		t:       lowerCaseASCII{},
+		src:     "Hello WORLD.",
+		dstSize: 3,
+		srcSize: 100,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small src",
+		t:       lowerCaseASCII{},
+		src:     "Hello WORLD.",
+		dstSize: 100,
+		srcSize: 4,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small buffers",
+		t:       lowerCaseASCII{},
+		src:     "Hello WORLD.",
+		dstSize: 3,
+		srcSize: 4,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "very small buffers",
+		t:       lowerCaseASCII{},
+		src:     "Hello WORLD.",
+		dstSize: 1,
+		srcSize: 1,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small dst with lookahead",
+		t:       lowerCaseASCIILookahead{},
+		src:     "Hello WORLD.",
+		dstSize: 3,
+		srcSize: 100,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small src with lookahead",
+		t:       lowerCaseASCIILookahead{},
+		src:     "Hello WORLD.",
+		dstSize: 100,
+		srcSize: 4,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "small buffers with lookahead",
+		t:       lowerCaseASCIILookahead{},
+		src:     "Hello WORLD.",
+		dstSize: 3,
+		srcSize: 4,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "very small buffers with lookahead",
+		t:       lowerCaseASCIILookahead{},
+		src:     "Hello WORLD.",
+		dstSize: 1,
+		srcSize: 2,
+		wantStr: "hello world.",
+	},
+
+	{
+		desc:    "user error",
+		t:       dontMentionX{},
+		src:     "The First Rule of Transform Club: don't mention Mister X, ever.",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "The First Rule of Transform Club: don't mention Mister ",
+		wantErr: errYouMentionedX,
+	},
+
+	{
+		desc:    "user error at end",
+		t:       errorAtEnd{},
+		src:     "All goes well until it doesn't.",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "All goes well until it doesn't.",
+		wantErr: errAtEnd,
+	},
+
+	{
+		desc:    "user error at end, incremental",
+		t:       errorAtEnd{},
+		src:     "All goes well until it doesn't.",
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: "All goes well until it doesn't.",
+		wantErr: errAtEnd,
+	},
+
+	{
+		desc:    "replace entire non-empty string with one byte",
+		t:       &replaceWithConstant{replacement: "X"},
+		src:     "none of this will be copied",
+		dstSize: 1,
+		srcSize: 10,
+		wantStr: "X",
+	},
+
+	{
+		desc:    "replace entire empty string with one byte",
+		t:       &replaceWithConstant{replacement: "X"},
+		src:     "",
+		dstSize: 1,
+		srcSize: 10,
+		wantStr: "X",
+	},
+
+	{
+		desc:    "replace entire empty string with seven bytes",
+		t:       &replaceWithConstant{replacement: "ABCDEFG"},
+		src:     "",
+		dstSize: 3,
+		srcSize: 10,
+		wantStr: "ABCDEFG",
+	},
+
+	{
+		desc:    "add an X (initialBufSize-1)",
+		t:       addAnXAtTheEnd{},
+		src:     aaa[:initialBufSize-1],
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: aaa[:initialBufSize-1] + "X",
+	},
+
+	{
+		desc:    "add an X (initialBufSize+0)",
+		t:       addAnXAtTheEnd{},
+		src:     aaa[:initialBufSize+0],
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: aaa[:initialBufSize+0] + "X",
+	},
+
+	{
+		desc:    "add an X (initialBufSize+1)",
+		t:       addAnXAtTheEnd{},
+		src:     aaa[:initialBufSize+1],
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: aaa[:initialBufSize+1] + "X",
+	},
+
+	{
+		desc:    "small buffers",
+		t:       dontMentionX{},
+		src:     "The First Rule of Transform Club: don't mention Mister X, ever.",
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: "The First Rule of Transform Club: don't mention Mister ",
+		wantErr: errYouMentionedX,
+	},
+
+	{
+		desc:    "very small buffers",
+		t:       dontMentionX{},
+		src:     "The First Rule of Transform Club: don't mention Mister X, ever.",
+		dstSize: 1,
+		srcSize: 1,
+		wantStr: "The First Rule of Transform Club: don't mention Mister ",
+		wantErr: errYouMentionedX,
+	},
+
+	{
+		desc:    "only transform at EOF",
+		t:       doublerAtEOF{},
+		src:     "this",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "tthhiiss",
+	},
+
+	{
+		desc:    "basic",
+		t:       rleDecode{},
+		src:     "1a2b3c10d11e0f1g",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "abbcccddddddddddeeeeeeeeeeeg",
+	},
+
+	{
+		desc:    "long",
+		t:       rleDecode{},
+		src:     "12a23b34c45d56e99z",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: strings.Repeat("a", 12) +
+			strings.Repeat("b", 23) +
+			strings.Repeat("c", 34) +
+			strings.Repeat("d", 45) +
+			strings.Repeat("e", 56) +
+			strings.Repeat("z", 99),
+	},
+
+	{
+		desc:    "tight buffers",
+		t:       rleDecode{},
+		src:     "1a2b3c10d11e0f1g",
+		dstSize: 11,
+		srcSize: 3,
+		wantStr: "abbcccddddddddddeeeeeeeeeeeg",
+	},
+
+	{
+		desc:    "short dst",
+		t:       rleDecode{},
+		src:     "1a2b3c10d11e0f1g",
+		dstSize: 10,
+		srcSize: 3,
+		wantStr: "abbcccdddddddddd",
+		wantErr: ErrShortDst,
+	},
+
+	{
+		desc:    "short src",
+		t:       rleDecode{},
+		src:     "1a2b3c10d11e0f1g",
+		dstSize: 11,
+		srcSize: 2,
+		ioSize:  2,
+		wantStr: "abbccc",
+		wantErr: ErrShortSrc,
+	},
+
+	{
+		desc:    "basic",
+		t:       rleEncode{},
+		src:     "abbcccddddddddddeeeeeeeeeeeg",
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "1a2b3c10d11e1g",
+	},
+
+	{
+		desc: "long",
+		t:    rleEncode{},
+		src: strings.Repeat("a", 12) +
+			strings.Repeat("b", 23) +
+			strings.Repeat("c", 34) +
+			strings.Repeat("d", 45) +
+			strings.Repeat("e", 56) +
+			strings.Repeat("z", 99),
+		dstSize: 100,
+		srcSize: 100,
+		wantStr: "12a23b34c45d56e99z",
+	},
+
+	{
+		desc:    "tight buffers",
+		t:       rleEncode{},
+		src:     "abbcccddddddddddeeeeeeeeeeeg",
+		dstSize: 3,
+		srcSize: 12,
+		wantStr: "1a2b3c10d11e1g",
+	},
+
+	{
+		desc:    "short dst",
+		t:       rleEncode{},
+		src:     "abbcccddddddddddeeeeeeeeeeeg",
+		dstSize: 2,
+		srcSize: 12,
+		wantStr: "1a2b3c",
+		wantErr: ErrShortDst,
+	},
+
+	{
+		desc:    "short src",
+		t:       rleEncode{},
+		src:     "abbcccddddddddddeeeeeeeeeeeg",
+		dstSize: 3,
+		srcSize: 11,
+		ioSize:  11,
+		wantStr: "1a2b3c10d",
+		wantErr: ErrShortSrc,
+	},
+
+	{
+		desc:    "allowStutter = false",
+		t:       rleEncode{allowStutter: false},
+		src:     "aaaabbbbbbbbccccddddd",
+		dstSize: 10,
+		srcSize: 10,
+		wantStr: "4a8b4c5d",
+	},
+
+	{
+		desc:    "allowStutter = true",
+		t:       rleEncode{allowStutter: true},
+		src:     "aaaabbbbbbbbccccddddd",
+		dstSize: 10,
+		srcSize: 10,
+		ioSize:  10,
+		wantStr: "4a6b2b4c4d1d",
+	},
+
+	{
+		desc:    "trickler",
+		t:       &trickler{},
+		src:     "abcdefghijklm",
+		dstSize: 3,
+		srcSize: 15,
+		wantStr: "abcdefghijklm",
+	},
+
+	{
+		desc:    "delayedTrickler",
+		t:       &delayedTrickler{},
+		src:     "abcdefghijklm",
+		dstSize: 3,
+		srcSize: 15,
+		wantStr: "abcdefghijklm",
+	},
+}
+
+func TestReader(t *testing.T) {
+	for _, tc := range testCases {
+		testtext.Run(t, tc.desc, func(t *testing.T) {
+			r := NewReader(strings.NewReader(tc.src), tc.t)
+			// Differently sized dst and src buffers are not part of the
+			// exported API. We override them manually.
+			r.dst = make([]byte, tc.dstSize)
+			r.src = make([]byte, tc.srcSize)
+			got, err := ioutil.ReadAll(r)
+			str := string(got)
+			if str != tc.wantStr || err != tc.wantErr {
+				t.Errorf("\ngot  %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr)
+			}
+		})
+	}
+}
+
+func TestWriter(t *testing.T) {
+	tests := append(testCases, chainTests()...)
+	for _, tc := range tests {
+		sizes := []int{1, 2, 3, 4, 5, 10, 100, 1000}
+		if tc.ioSize > 0 {
+			sizes = []int{tc.ioSize}
+		}
+		for _, sz := range sizes {
+			testtext.Run(t, fmt.Sprintf("%s/%d", tc.desc, sz), func(t *testing.T) {
+				bb := &bytes.Buffer{}
+				w := NewWriter(bb, tc.t)
+				// Differently sized dst and src buffers are not part of the
+				// exported API. We override them manually.
+				w.dst = make([]byte, tc.dstSize)
+				w.src = make([]byte, tc.srcSize)
+				src := make([]byte, sz)
+				var err error
+				for b := tc.src; len(b) > 0 && err == nil; {
+					n := copy(src, b)
+					b = b[n:]
+					m := 0
+					m, err = w.Write(src[:n])
+					if m != n && err == nil {
+						t.Errorf("did not consume all bytes %d < %d", m, n)
+					}
+				}
+				if err == nil {
+					err = w.Close()
+				}
+				str := bb.String()
+				if str != tc.wantStr || err != tc.wantErr {
+					t.Errorf("\ngot  %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr)
+				}
+			})
+		}
+	}
+}
+
+func TestNop(t *testing.T) {
+	testCases := []struct {
+		str     string
+		dstSize int
+		err     error
+	}{
+		{"", 0, nil},
+		{"", 10, nil},
+		{"a", 0, ErrShortDst},
+		{"a", 1, nil},
+		{"a", 10, nil},
+	}
+	for i, tc := range testCases {
+		dst := make([]byte, tc.dstSize)
+		nDst, nSrc, err := Nop.Transform(dst, []byte(tc.str), true)
+		want := tc.str
+		if tc.dstSize < len(want) {
+			want = want[:tc.dstSize]
+		}
+		if got := string(dst[:nDst]); got != want || err != tc.err || nSrc != nDst {
+			t.Errorf("%d:\ngot %q, %d, %v\nwant %q, %d, %v", i, got, nSrc, err, want, nDst, tc.err)
+		}
+	}
+}
+
+func TestDiscard(t *testing.T) {
+	testCases := []struct {
+		str     string
+		dstSize int
+	}{
+		{"", 0},
+		{"", 10},
+		{"a", 0},
+		{"ab", 10},
+	}
+	for i, tc := range testCases {
+		nDst, nSrc, err := Discard.Transform(make([]byte, tc.dstSize), []byte(tc.str), true)
+		if nDst != 0 || nSrc != len(tc.str) || err != nil {
+			t.Errorf("%d:\ngot %q, %d, %v\nwant 0, %d, nil", i, nDst, nSrc, err, len(tc.str))
+		}
+	}
+}
+
+// mkChain creates a Chain transformer. x must be alternating between transformer
+// and bufSize, like T, (sz, T)*
+func mkChain(x ...interface{}) *chain {
+	t := []Transformer{}
+	for i := 0; i < len(x); i += 2 {
+		t = append(t, x[i].(Transformer))
+	}
+	c := Chain(t...).(*chain)
+	for i, j := 1, 1; i < len(x); i, j = i+2, j+1 {
+		c.link[j].b = make([]byte, x[i].(int))
+	}
+	return c
+}
+
+func chainTests() []testCase {
+	return []testCase{
+		{
+			desc:     "nil error",
+			t:        mkChain(rleEncode{}, 100, lowerCaseASCII{}),
+			src:      "ABB",
+			dstSize:  100,
+			srcSize:  100,
+			wantStr:  "1a2b",
+			wantErr:  nil,
+			wantIter: 1,
+		},
+
+		{
+			desc:    "short dst buffer",
+			t:       mkChain(lowerCaseASCII{}, 3, rleDecode{}),
+			src:     "1a2b3c10d11e0f1g",
+			dstSize: 10,
+			srcSize: 3,
+			wantStr: "abbcccdddddddddd",
+			wantErr: ErrShortDst,
+		},
+
+		{
+			desc:    "short internal dst buffer",
+			t:       mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop),
+			src:     "1a2b3c10d11e0f1g",
+			dstSize: 100,
+			srcSize: 3,
+			wantStr: "abbcccdddddddddd",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "short internal dst buffer from input",
+			t:       mkChain(rleDecode{}, 10, Nop),
+			src:     "1a2b3c10d11e0f1g",
+			dstSize: 100,
+			srcSize: 3,
+			wantStr: "abbcccdddddddddd",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "empty short internal dst buffer",
+			t:       mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop),
+			src:     "4a7b11e0f1g",
+			dstSize: 100,
+			srcSize: 3,
+			wantStr: "aaaabbbbbbb",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "empty short internal dst buffer from input",
+			t:       mkChain(rleDecode{}, 10, Nop),
+			src:     "4a7b11e0f1g",
+			dstSize: 100,
+			srcSize: 3,
+			wantStr: "aaaabbbbbbb",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:     "short internal src buffer after full dst buffer",
+			t:        mkChain(Nop, 5, rleEncode{}, 10, Nop),
+			src:      "cccccddddd",
+			dstSize:  100,
+			srcSize:  100,
+			wantStr:  "",
+			wantErr:  errShortInternal,
+			wantIter: 1,
+		},
+
+		{
+			desc:    "short internal src buffer after short dst buffer; test lastFull",
+			t:       mkChain(rleDecode{}, 5, rleEncode{}, 4, Nop),
+			src:     "2a1b4c6d",
+			dstSize: 100,
+			srcSize: 100,
+			wantStr: "2a1b",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:     "short internal src buffer after successful complete fill",
+			t:        mkChain(Nop, 3, rleDecode{}),
+			src:      "123a4b",
+			dstSize:  4,
+			srcSize:  3,
+			wantStr:  "",
+			wantErr:  errShortInternal,
+			wantIter: 1,
+		},
+
+		{
+			desc:    "short internal src buffer after short dst buffer; test lastFull",
+			t:       mkChain(rleDecode{}, 5, rleEncode{}),
+			src:     "2a1b4c6d",
+			dstSize: 4,
+			srcSize: 100,
+			wantStr: "2a1b",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "short src buffer",
+			t:       mkChain(rleEncode{}, 5, Nop),
+			src:     "abbcccddddeeeee",
+			dstSize: 4,
+			srcSize: 4,
+			ioSize:  4,
+			wantStr: "1a2b3c",
+			wantErr: ErrShortSrc,
+		},
+
+		{
+			desc:     "process all in one go",
+			t:        mkChain(rleEncode{}, 5, Nop),
+			src:      "abbcccddddeeeeeffffff",
+			dstSize:  100,
+			srcSize:  100,
+			wantStr:  "1a2b3c4d5e6f",
+			wantErr:  nil,
+			wantIter: 1,
+		},
+
+		{
+			desc:    "complete processing downstream after error",
+			t:       mkChain(dontMentionX{}, 2, rleDecode{}, 5, Nop),
+			src:     "3a4b5eX",
+			dstSize: 100,
+			srcSize: 100,
+			ioSize:  100,
+			wantStr: "aaabbbbeeeee",
+			wantErr: errYouMentionedX,
+		},
+
+		{
+			desc:    "return downstream fatal errors first (followed by short dst)",
+			t:       mkChain(dontMentionX{}, 8, rleDecode{}, 4, Nop),
+			src:     "3a4b5eX",
+			dstSize: 100,
+			srcSize: 100,
+			ioSize:  100,
+			wantStr: "aaabbbb",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "return downstream fatal errors first (followed by short src)",
+			t:       mkChain(dontMentionX{}, 5, Nop, 1, rleDecode{}),
+			src:     "1a5bX",
+			dstSize: 100,
+			srcSize: 100,
+			ioSize:  100,
+			wantStr: "",
+			wantErr: errShortInternal,
+		},
+
+		{
+			desc:    "short internal",
+			t:       mkChain(Nop, 11, rleEncode{}, 3, Nop),
+			src:     "abbcccddddddddddeeeeeeeeeeeg",
+			dstSize: 3,
+			srcSize: 100,
+			wantStr: "1a2b3c10d",
+			wantErr: errShortInternal,
+		},
+	}
+}
+
+func doTransform(tc testCase) (res string, iter int, err error) {
+	tc.t.Reset()
+	dst := make([]byte, tc.dstSize)
+	out, in := make([]byte, 0, 2*len(tc.src)), []byte(tc.src)
+	for {
+		iter++
+		src, atEOF := in, true
+		if len(src) > tc.srcSize {
+			src, atEOF = src[:tc.srcSize], false
+		}
+		nDst, nSrc, err := tc.t.Transform(dst, src, atEOF)
+		out = append(out, dst[:nDst]...)
+		in = in[nSrc:]
+		switch {
+		case err == nil && len(in) != 0:
+		case err == ErrShortSrc && nSrc > 0:
+		case err == ErrShortDst && (nDst > 0 || nSrc > 0):
+		default:
+			return string(out), iter, err
+		}
+	}
+}
+
+func TestChain(t *testing.T) {
+	if c, ok := Chain().(nop); !ok {
+		t.Errorf("empty chain: %v; want Nop", c)
+	}
+
+	// Test Chain for a single Transformer.
+	for _, tc := range testCases {
+		tc.t = Chain(tc.t)
+		str, _, err := doTransform(tc)
+		if str != tc.wantStr || err != tc.wantErr {
+			t.Errorf("%s:\ngot  %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr)
+		}
+	}
+
+	tests := chainTests()
+	sizes := []int{1, 2, 3, 4, 5, 7, 10, 100, 1000}
+	addTest := func(tc testCase, t *chain) {
+		if t.link[0].t != tc.t && tc.wantErr == ErrShortSrc {
+			tc.wantErr = errShortInternal
+		}
+		if t.link[len(t.link)-2].t != tc.t && tc.wantErr == ErrShortDst {
+			tc.wantErr = errShortInternal
+		}
+		tc.t = t
+		tests = append(tests, tc)
+	}
+	for _, tc := range testCases {
+		for _, sz := range sizes {
+			tt := tc
+			tt.dstSize = sz
+			addTest(tt, mkChain(tc.t, tc.dstSize, Nop))
+			addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 2, Nop))
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop))
+			if sz >= tc.dstSize && (tc.wantErr != ErrShortDst || sz == tc.dstSize) {
+				addTest(tt, mkChain(Nop, tc.srcSize, tc.t))
+				addTest(tt, mkChain(Nop, 100, Nop, tc.srcSize, tc.t))
+			}
+		}
+	}
+	for _, tc := range testCases {
+		tt := tc
+		tt.dstSize = 1
+		tt.wantStr = ""
+		addTest(tt, mkChain(tc.t, tc.dstSize, Discard))
+		addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Discard))
+		addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, tc.dstSize, Discard))
+	}
+	for _, tc := range testCases {
+		tt := tc
+		tt.dstSize = 100
+		tt.wantStr = strings.Replace(tc.src, "0f", "", -1)
+		// Chain encoders and decoders.
+		if _, ok := tc.t.(rleEncode); ok && tc.wantErr == nil {
+			addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 1000, rleDecode{}))
+			addTest(tt, mkChain(tc.t, tc.dstSize, Nop, tc.dstSize, rleDecode{}))
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}))
+			// decoding needs larger destinations
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, rleDecode{}, 100, Nop))
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}, 100, Nop))
+		} else if _, ok := tc.t.(rleDecode); ok && tc.wantErr == nil {
+			// The internal buffer size may need to be the sum of the maximum segment
+			// size of the two encoders!
+			addTest(tt, mkChain(tc.t, 2*tc.dstSize, rleEncode{}))
+			addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 101, rleEncode{}))
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleEncode{}))
+			addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 200, rleEncode{}, 100, Nop))
+		}
+	}
+	for _, tc := range tests {
+		str, iter, err := doTransform(tc)
+		mi := tc.wantIter != 0 && tc.wantIter != iter
+		if str != tc.wantStr || err != tc.wantErr || mi {
+			t.Errorf("%s:\ngot  iter:%d, %q, %v\nwant iter:%d, %q, %v", tc, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr)
+		}
+		break
+	}
+}
+
+func TestRemoveFunc(t *testing.T) {
+	filter := RemoveFunc(func(r rune) bool {
+		return strings.IndexRune("ab\u0300\u1234,", r) != -1
+	})
+	tests := []testCase{
+		{
+			src:     ",",
+			wantStr: "",
+		},
+
+		{
+			src:     "c",
+			wantStr: "c",
+		},
+
+		{
+			src:     "\u2345",
+			wantStr: "\u2345",
+		},
+
+		{
+			src:     "tschüß",
+			wantStr: "tschüß",
+		},
+
+		{
+			src:     ",до,свидания,",
+			wantStr: "досвидания",
+		},
+
+		{
+			src:     "a\xbd\xb2=\xbc ⌘",
+			wantStr: "\uFFFD\uFFFD=\uFFFD ⌘",
+		},
+
+		{
+			// If we didn't replace illegal bytes with RuneError, the result
+			// would be \u0300 or the code would need to be more complex.
+			src:     "\xcc\u0300\x80",
+			wantStr: "\uFFFD\uFFFD",
+		},
+
+		{
+			src:      "\xcc\u0300\x80",
+			dstSize:  3,
+			wantStr:  "\uFFFD\uFFFD",
+			wantIter: 2,
+		},
+
+		{
+			// Test a long buffer greater than the internal buffer size
+			src:      "hello\xcc\xcc\xccworld",
+			srcSize:  13,
+			wantStr:  "hello\uFFFD\uFFFD\uFFFDworld",
+			wantIter: 1,
+		},
+
+		{
+			src:     "\u2345",
+			dstSize: 2,
+			wantStr: "",
+			wantErr: ErrShortDst,
+		},
+
+		{
+			src:     "\xcc",
+			dstSize: 2,
+			wantStr: "",
+			wantErr: ErrShortDst,
+		},
+
+		{
+			src:     "\u0300",
+			dstSize: 2,
+			srcSize: 1,
+			wantStr: "",
+			wantErr: ErrShortSrc,
+		},
+
+		{
+			t: RemoveFunc(func(r rune) bool {
+				return r == utf8.RuneError
+			}),
+			src:     "\xcc\u0300\x80",
+			wantStr: "\u0300",
+		},
+	}
+
+	for _, tc := range tests {
+		tc.desc = tc.src
+		if tc.t == nil {
+			tc.t = filter
+		}
+		if tc.dstSize == 0 {
+			tc.dstSize = 100
+		}
+		if tc.srcSize == 0 {
+			tc.srcSize = 100
+		}
+		str, iter, err := doTransform(tc)
+		mi := tc.wantIter != 0 && tc.wantIter != iter
+		if str != tc.wantStr || err != tc.wantErr || mi {
+			t.Errorf("%+q:\ngot  iter:%d, %+q, %v\nwant iter:%d, %+q, %v", tc.src, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr)
+		}
+
+		tc.src = str
+		idem, _, _ := doTransform(tc)
+		if str != idem {
+			t.Errorf("%+q: found %+q; want %+q", tc.src, idem, str)
+		}
+	}
+}
+
+func testString(t *testing.T, f func(Transformer, string) (string, int, error)) {
+	for _, tt := range append(testCases, chainTests()...) {
+		if tt.desc == "allowStutter = true" {
+			// We don't have control over the buffer size, so we eliminate tests
+			// that depend on a specific buffer size being set.
+			continue
+		}
+		if tt.wantErr == ErrShortDst || tt.wantErr == ErrShortSrc {
+			// The result string will be different.
+			continue
+		}
+		testtext.Run(t, tt.desc, func(t *testing.T) {
+			got, n, err := f(tt.t, tt.src)
+			if tt.wantErr != err {
+				t.Errorf("error: got %v; want %v", err, tt.wantErr)
+			}
+			// Check that err == nil implies that n == len(tt.src). Note that vice
+			// versa isn't necessarily true.
+			if err == nil && n != len(tt.src) {
+				t.Errorf("err == nil: got %d bytes, want %d", n, err)
+			}
+			if got != tt.wantStr {
+				t.Errorf("string: got %q; want %q", got, tt.wantStr)
+			}
+		})
+	}
+}
+
+func TestBytes(t *testing.T) {
+	testString(t, func(z Transformer, s string) (string, int, error) {
+		b, n, err := Bytes(z, []byte(s))
+		return string(b), n, err
+	})
+}
+
+func TestAppend(t *testing.T) {
+	// Create a bunch of subtests for different buffer sizes.
+	testCases := [][]byte{
+		nil,
+		make([]byte, 0, 0),
+		make([]byte, 0, 1),
+		make([]byte, 1, 1),
+		make([]byte, 1, 5),
+		make([]byte, 100, 100),
+		make([]byte, 100, 200),
+	}
+	for _, tc := range testCases {
+		testString(t, func(z Transformer, s string) (string, int, error) {
+			b, n, err := Append(z, tc, []byte(s))
+			return string(b[len(tc):]), n, err
+		})
+	}
+}
+
+func TestString(t *testing.T) {
+	testtext.Run(t, "transform", func(t *testing.T) { testString(t, String) })
+
+	// Overrun the internal destination buffer.
+	for i, s := range []string{
+		aaa[:1*initialBufSize-1],
+		aaa[:1*initialBufSize+0],
+		aaa[:1*initialBufSize+1],
+		AAA[:1*initialBufSize-1],
+		AAA[:1*initialBufSize+0],
+		AAA[:1*initialBufSize+1],
+		AAA[:2*initialBufSize-1],
+		AAA[:2*initialBufSize+0],
+		AAA[:2*initialBufSize+1],
+		aaa[:1*initialBufSize-2] + "A",
+		aaa[:1*initialBufSize-1] + "A",
+		aaa[:1*initialBufSize+0] + "A",
+		aaa[:1*initialBufSize+1] + "A",
+	} {
+		testtext.Run(t, fmt.Sprint("dst buffer test using lower/", i), func(t *testing.T) {
+			got, _, _ := String(lowerCaseASCII{}, s)
+			if want := strings.ToLower(s); got != want {
+				t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want))
+			}
+		})
+	}
+
+	// Overrun the internal source buffer.
+	for i, s := range []string{
+		aaa[:1*initialBufSize-1],
+		aaa[:1*initialBufSize+0],
+		aaa[:1*initialBufSize+1],
+		aaa[:2*initialBufSize+1],
+		aaa[:2*initialBufSize+0],
+		aaa[:2*initialBufSize+1],
+	} {
+		testtext.Run(t, fmt.Sprint("src buffer test using rleEncode/", i), func(t *testing.T) {
+			got, _, _ := String(rleEncode{}, s)
+			if want := fmt.Sprintf("%da", len(s)); got != want {
+				t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want))
+			}
+		})
+	}
+
+	// Test allocations for non-changing strings.
+	// Note we still need to allocate a single buffer.
+	for i, s := range []string{
+		"",
+		"123456789",
+		aaa[:initialBufSize-1],
+		aaa[:initialBufSize+0],
+		aaa[:initialBufSize+1],
+		aaa[:10*initialBufSize],
+	} {
+		testtext.Run(t, fmt.Sprint("alloc/", i), func(t *testing.T) {
+			if n := testtext.AllocsPerRun(5, func() { String(&lowerCaseASCIILookahead{}, s) }); n > 1 {
+				t.Errorf("#allocs was %f; want 1", n)
+			}
+		})
+	}
+}
+
+// TestBytesAllocation tests that buffer growth stays limited with the trickler
+// transformer, which behaves oddly but within spec. In case buffer growth is
+// not correctly handled, the test will either panic with a failed allocation or
+// thrash. To ensure the tests terminate under the last condition, we time out
+// after some sufficiently long period of time.
+func TestBytesAllocation(t *testing.T) {
+	done := make(chan bool)
+	go func() {
+		in := bytes.Repeat([]byte{'a'}, 1000)
+		tr := trickler(make([]byte, 1))
+		Bytes(&tr, in)
+		done <- true
+	}()
+	select {
+	case <-done:
+	case <-time.After(3 * time.Second):
+		t.Error("time out, likely due to excessive allocation")
+	}
+}
+
+// TestStringAllocation tests that buffer growth stays limited with the trickler
+// transformer, which behaves oddly but within spec. In case buffer growth is
+// not correctly handled, the test will either panic with a failed allocation or
+// thrash. To ensure the tests terminate under the last condition, we time out
+// after some sufficiently long period of time.
+func TestStringAllocation(t *testing.T) {
+	done := make(chan bool)
+	go func() {
+		tr := trickler(make([]byte, 1))
+		String(&tr, aaa[:1000])
+		done <- true
+	}()
+	select {
+	case <-done:
+	case <-time.After(3 * time.Second):
+		t.Error("time out, likely due to excessive allocation")
+	}
+}
+
+func BenchmarkStringLowerEmpty(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		String(&lowerCaseASCIILookahead{}, "")
+	}
+}
+
+func BenchmarkStringLowerIdentical(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		String(&lowerCaseASCIILookahead{}, aaa[:4096])
+	}
+}
+
+func BenchmarkStringLowerChanged(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		String(&lowerCaseASCIILookahead{}, AAA[:4096])
+	}
+}
+
+var (
+	aaa = strings.Repeat("a", 4096)
+	AAA = strings.Repeat("A", 4096)
+)